Skip to content

Conversation

@weihanglo
Copy link
Member

What does this PR try to resolve?

This reserves future possibility for us to support globa syntax and
templated paths.

Addressing #16284 (comment)

Which we want to disallow to reserve for future.
This reserves future possibility for us to support globa syntax and
templated paths.

Addressing rust-lang#16284 (comment)
@rustbot rustbot added A-configuration Area: cargo config files and env vars S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 21, 2025
@rustbot
Copy link
Collaborator

rustbot commented Nov 21, 2025

r? @ehuss

rustbot has assigned @ehuss.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@epage epage added this pull request to the merge queue Nov 21, 2025
@weihanglo weihanglo added the Z-config-include Nightly: `include` config key label Nov 21, 2025
Merged via the queue into rust-lang:master with commit 2b7dbd9 Nov 21, 2025
26 checks passed
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 21, 2025
weihanglo added a commit to weihanglo/cargo that referenced this pull request Nov 21, 2025
# Stabilization report

## Summary

The `include` key in Cargo configuration files allows loading
additional config files, enabling better organization, sharing, and
management of Cargo configurations across projects and environments.

This feature has been available under the `-Zconfig-include` flag
since 2019 (Cargo 1.42) and has seen real-world usage.

The stabilization includes support for multiple syntax forms and the
`optional` field, which were added in October 2025 based on user
feedback.

Tracking issue: rust-lang#7723

### What is stabilized

The `include` configuration key allows loading additional config files.

**Supported syntax:**

- String: `include = "path.toml"`
- Array: `include = ["a.toml", "b.toml"]`
- Inline tables: `include = [{ path = "optional.toml", optional = true }]`
- Array of tables: `[[include]]` with `path` and `optional` fields

**Key behaviors:**

- Paths are relative to the including config file and must end with
  `.toml`
- Glob syntax and templated paths (with `{}` braces} are disallowed
  in paths.
- Merge follows precedence order: included files (left-to-right) →
  parent config
- `optional = true` silently skips missing files (default: `false`)
- Cyclic includes are detected and reported as errors

See the config documentation for complete details and examples.

### Future extensions

Several potential extensions are not implemented at this time:

* Glob patterns: like `include = "config.d/*.toml"` — rust-lang#9306
* Conditional include: conditions like gitconfig's `includeIf` —
  rust-lang#7723 (comment)
* Variable substitution and template: placeholders like `{CONFIG_DIR}`
  or `{CARGO_HOME}` — rust-lang#15769
* Implicit-include: like `.cargo/config.user.toml` or `.cargo/config.d`
  for config fragments — [#t-cargo > Built-in
  &rust-lang#96;.cargo/config.local.toml&rust-lang#96;for non-committed
  config](https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/Built-in.20.60.2Ecargo.2Fconfig.2Elocal.2Etoml.60for.20non-committed.20config/with/558705263)
* Environment variable include support: like
  `CARGO_INCLUDE=path/to/config.toml` —
  rust-lang#6728

See "Doors closed" for more.

## Design

### Key evolution

All significant changes occurred during the unstable period
(2019-2024) and were approved by the Cargo team.

**1. File naming restrictions** (rust-lang#12298, 2023-06-21) (rust-lang#16285,
2025-11-21)

The syntax has a couple restrictions:

* File path should end with `.toml` extension
* File path should not contain glob syntax or template braces

The team considered the restriction was reasonable. The restriction
applies to config file discovery but not to `--config` CLI arguments
which has already been stabilized.

**2. Loading precedence for arrays**

Config values in array elements are loaded left to right, with later
values taking precedence. The parent config file's values always take
precedence over included configs. This provides intuitive layering
behavior.

**3. Syntax complexity** (rust-lang#16174, 2025-10-30)

The feature started with simple string/array syntax. The team debated
and decided to add table syntax before stabilization to allow future
extensions.

**4. Optional includes by default vs. explicit** (rust-lang#16180, 2025-10-31)

Some users wanted missing files to be silently ignored by default for
local customization workflows. Others wanted errors to catch typos.
The team chose to error by default but added an explicit `optional =
true` field, requiring users to be intentional about optional
behavior.

### Nightly extensions

No nightly-only extensions remain. The feature is fully stabilized as
implemented.

### Doors closed

**This stabilization commits to**:

1. Supporting the `include` key in Cargo configuration
2. Relative path resolution from the including config file
3. Left-to-right merge order for arrays
4. Parent config taking precedence over includes
6. The `path` and `optional` fields in table syntax

**This does NOT prevent**:

- Adding glob/wildcard support
- Adding conditional includes
- Adding variable substitution and template

The `[[include]]` table syntax could optionally have a field to enable
the future extensions above. For example,

```toml
[[include]]
path = "path/config/*.toml"
glob = true

[[include]]
path = "path/*/config.toml"
if = "<some-condition>"

[[include]]
path = "path/*/config.toml"
templatized = true
```

**This MAY prevent**:

* Adding new implicit-include for user local config or config
  fragments directory

As we are going to allow all file paths. Adding any implicit includes
after stabilization might break the merge precedence if people already
include those paths.

However, implicit-include for config fragments (e.g., `include =
[".cargo/config.toml/"]`) can be supported in the future without
breaking changes, if `config.toml/` is a directory.

## Feedback

### Call for testing

No formal "call for testing" was issued, but the feature has been
available under `-Zconfig-include` since Cargo 1.42 (2019) and has
seen real-world adoption.

### Use cases

Users reported use cases:

- **Sharing flags and environment conditionally**: [Tock
  OS](https://github.com/tock/tock),
  [esp-hal](https://github.com/esp-rs/esp-hal), rtos, and some FFI
  libraries use it for preset management across multiple board
  configurations for different hardware platforms, architectures, and
  downstream crates. A board's config (used by entering its
  directory) is defined by pulling from role-based config slices.

- **Beyond hierarchical discovery**: Some use cases require explicit
  includes because configs need to be loaded from locations outside
  the hierarchical path, or need to be conditionally included based on
  per-package or per-machine requirements that can't rely on the
  directory structure alone. This usually happens in a meta build
  system that generates configs, especially when setting `CARGO_HOME`
  to a different location off the hierarchical path.

- **User and project configuration**: Projects with checked-in configs
  (e.g., `[profile.test] debug = false` for CI) can allow developers
  to override settings locally without modifying the checked-in file.
  Developers can include an optional `.cargo/local-config.toml`
  without using git workarounds like `update-index --assume-unchanged`.

### Coverage

Test coverage is comprehensive in `tests/testsuite/config_include.rs`:

- Merge behavior: left-to-right order, hierarchy interaction
- Path handling: relative paths, different directory structures
- Cycle detection: Direct and indirect cycles
- Error cases: missing files, invalid paths, wrong extensions, missing
  required fields
- Syntax variations: string, array, inline table, array of tables
- Optional includes: missing optional files, mixed optional/required
- CLI integration: includes from `--config` arguments
- Forward compatibility: unknown table fields

### Known limitations

Issue rust-lang#15769 tracks inconsistent relative path behavior between
`include` paths (relative to config file) and other config paths like
`build.target-dir` (relative to cargo root). This is considered a
known limitation and confusion that can be addressed separately and
doesn't block stabilization.

No other known limitations blocking stabilization.

## History

- 2019-02-25: Original proposal (rust-lang#6699)
- 2019-12-19: initial implementation (rust-lang#7649)
- 2023-06-21: file extension restriction added (rust-lang#12298)
- 2025-10-30: table syntax support added (rust-lang#16174)
- 2025-10-31: optional field support added (rust-lang#16180)
- 2025-11-21: glob and template syntax restriction added (rust-lang#16285)

## Acknowledgments

Contributors to this feature:

- `@ehuss` for initial implementation and design
- `@weihanglo` for extra syntax support and enhancement
- `@rust-lang/cargo` team for the support, review and feedback
- All users providing feedback in rust-lang#7723
weihanglo added a commit to weihanglo/cargo that referenced this pull request Nov 21, 2025
# Stabilization report

## Summary

The `include` key in Cargo configuration files allows loading
additional config files, enabling better organization, sharing, and
management of Cargo configurations across projects and environments.

This feature has been available under the `-Zconfig-include` flag
since 2019 (Cargo 1.42) and has seen real-world usage.

The stabilization includes support for multiple syntax forms and the
`optional` field, which were added in October 2025 based on user
feedback.

Tracking issue: rust-lang#7723

### What is stabilized

The `include` configuration key allows loading additional config files.

**Supported syntax:**

- String: `include = "path.toml"`
- Array: `include = ["a.toml", "b.toml"]`
- Inline tables: `include = [{ path = "optional.toml", optional = true }]`
- Array of tables: `[[include]]` with `path` and `optional` fields

**Key behaviors:**

- Paths are relative to the including config file and must end with
  `.toml`
- Glob syntax and templated paths (with `{}` braces} are disallowed
  in paths.
- Merge follows precedence order: included files (left-to-right) →
  parent config
- `optional = true` silently skips missing files (default: `false`)
- Cyclic includes are detected and reported as errors

See the config documentation for complete details and examples.

### Future extensions

Several potential extensions are not implemented at this time:

* Glob patterns: like `include = "config.d/*.toml"` — rust-lang#9306
* Conditional include: conditions like gitconfig's `includeIf` —
  rust-lang#7723 (comment)
* Variable substitution and template: placeholders like `{CONFIG_DIR}`
  or `{CARGO_HOME}` — rust-lang#15769
* Implicit-include: like `.cargo/config.user.toml` or `.cargo/config.d`
  for config fragments — [#t-cargo > Built-in
  &rust-lang#96;.cargo/config.local.toml&rust-lang#96;for non-committed
  config](https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/Built-in.20.60.2Ecargo.2Fconfig.2Elocal.2Etoml.60for.20non-committed.20config/with/558705263)
* Environment variable include support: like
  `CARGO_INCLUDE=path/to/config.toml` —
  rust-lang#6728

See "Doors closed" for more.

## Design

### Key evolution

All significant changes occurred during the unstable period
(2019-2024) and were approved by the Cargo team.

**1. File naming restrictions** (rust-lang#12298, 2023-06-21) (rust-lang#16285,
2025-11-21)

The syntax has a couple restrictions:

* Path must end with `.toml` extension
* Path must not contain glob syntax or template braces

The team considered the restriction was reasonable. The restriction
applies to config file discovery but not to `--config` CLI arguments
which has already been stabilized.

**2. Loading precedence for arrays**

Config values in array elements are loaded left to right, with later
values taking precedence. The parent config file's values always take
precedence over included configs. This provides intuitive layering
behavior.

**3. Syntax complexity** (rust-lang#16174, 2025-10-30)

The feature started with simple string/array syntax. The team debated
and decided to add table syntax before stabilization to allow future
extensions.

**4. Optional includes by default vs. explicit** (rust-lang#16180, 2025-10-31)

Some users wanted missing files to be silently ignored by default for
local customization workflows. Others wanted errors to catch typos.
The team chose to error by default but added an explicit `optional =
true` field, requiring users to be intentional about optional
behavior.

### Nightly extensions

No nightly-only extensions remain. The feature is fully stabilized as
implemented.

### Doors closed

**This stabilization commits to**:

1. Supporting the `include` key in Cargo configuration
2. Relative path resolution from the including config file
3. Left-to-right merge order for arrays
4. Parent config taking precedence over includes
5. The `path` and `optional` fields in table syntax

**This does NOT prevent**:

- Adding glob/wildcard support
- Adding conditional includes
- Adding variable substitution and template

**This MAY prevent**:

* Adding new implicit-include for user local config or config
  fragments directory

As we are going to allow all file paths. Adding any implicit includes
after stabilization might break the merge precedence if people already
include those paths.

The only possible way to support it is accepting `.cargo/config.toml/`
as a directory and treat it as a config fragments directory.
`.cargo/config.toml` (and the legacy `.cargo/config`) is the only path
Cargo reserves.

## Feedback

### Call for testing

No formal "call for testing" was issued, but the feature has been
available under `-Zconfig-include` since Cargo 1.42 (2019) and has
seen real-world adoption.

### Use cases

Users reported use cases:

- **Sharing flags and environment conditionally**: [Tock
  OS](https://github.com/tock/tock),
  [esp-hal](https://github.com/esp-rs/esp-hal), rtos, and some FFI
  libraries use it for preset management across multiple board
  configurations for different hardware platforms, architectures, and
  downstream crates. A board's config (used by entering its
  directory) is defined by pulling from role-based config slices.

- **Beyond hierarchical discovery**: Some use cases require explicit
  includes because configs need to be loaded from locations outside
  the hierarchical path, or need to be conditionally included based on
  per-package or per-machine requirements that can't rely on the
  directory structure alone. This usually happens in a meta build
  system that generates configs, especially when setting `CARGO_HOME`
  to a different location off the hierarchical path.

- **User and project configuration**: Projects with checked-in configs
  (e.g., `[profile.test] debug = false` for CI) can allow developers
  to override settings locally without modifying the checked-in file.
  Developers can include an optional `.cargo/local-config.toml`
  without using git workarounds like `update-index --assume-unchanged`.

### Coverage

Test coverage is comprehensive in `tests/testsuite/config_include.rs`:

- Merge behavior: left-to-right order, hierarchy interaction
- Path handling: relative paths, different directory structures
- Cycle detection: Direct and indirect cycles
- Error cases: missing files, invalid paths, wrong extensions, missing
  required fields
- Syntax variations: string, array, inline table, array of tables
- Optional includes: missing optional files, mixed optional/required
- CLI integration: includes from `--config` arguments
- Forward compatibility: unknown table fields

### Known limitations

Issue rust-lang#15769 tracks inconsistent relative path behavior between
`include` paths (relative to config file) and other config paths like
`build.target-dir` (relative to cargo root). This is considered a
known limitation and confusion that can be addressed separately and
doesn't block stabilization.

No other known limitations blocking stabilization.

## History

- 2019-02-25: Original proposal (rust-lang#6699)
- 2019-12-19: initial implementation (rust-lang#7649)
- 2023-06-21: file extension restriction added (rust-lang#12298)
- 2025-10-30: table syntax support added (rust-lang#16174)
- 2025-10-31: optional field support added (rust-lang#16180)
- 2025-11-21: glob and template syntax restriction added (rust-lang#16285)

## Acknowledgments

Contributors to this feature:

- `@ehuss` for initial implementation and design
- `@weihanglo` for extra syntax support and enhancement
- `@rust-lang/cargo` team for the support, review and feedback
- All users providing feedback in rust-lang#7723
bors added a commit to rust-lang/rust that referenced this pull request Nov 22, 2025
Update cargo submodule

7 commits in 5c0343317ce45d2ec17ecf41eaa473a02d73e29c..9fa462fe3a81e07e0bfdcc75c29d312c55113ebb
2025-11-18 19:05:44 +0000 to 2025-11-21 20:49:51 +0000
- Enable CARGO_CFG_DEBUG_ASSERTIONS in build scripts based on profile (rust-lang/cargo#16160)
- fix(config-include): disallow glob and template syntax (rust-lang/cargo#16285)
- test(config-include): include always relative to including config (rust-lang/cargo#16286)
- docs(guide): When suggesting alt dev profile, link to related issue (rust-lang/cargo#16275)
- refactor(timings): separate data collection and presentation (rust-lang/cargo#16282)
- test(build-std): Add test for LTO (rust-lang/cargo#16277)
- fix(bindeps): do not propagate artifact dependency to proc macro or build deps (rust-lang/cargo#15788)

r? ghost
@rustbot rustbot added this to the 1.93.0 milestone Nov 22, 2025
weihanglo added a commit to weihanglo/cargo that referenced this pull request Nov 24, 2025
# Stabilization report

## Summary

The `include` key in Cargo configuration files allows loading
additional config files, enabling better organization, sharing, and
management of Cargo configurations across projects and environments.

This feature has been available under the `-Zconfig-include` flag
since 2019 (Cargo 1.42) and has seen real-world usage.

The stabilization includes support for multiple syntax forms and the
`optional` field, which were added in October 2025 based on user
feedback.

Tracking issue: rust-lang#7723

### What is stabilized

The `include` configuration key allows loading additional config files.

**Supported syntax:**

- String: `include = "path.toml"`
- Array: `include = ["a.toml", "b.toml"]`
- Inline tables: `include = [{ path = "optional.toml", optional = true }]`
- Array of tables: `[[include]]` with `path` and `optional` fields

**Key behaviors:**

- Paths are relative to the including config file and must end with
  `.toml`
- Glob syntax and templated paths (with `{}` braces} are disallowed
  in paths.
- Merge follows precedence order: included files (left-to-right) →
  parent config
- `optional = true` silently skips missing files (default: `false`)
- Cyclic includes are detected and reported as errors

See the config documentation for complete details and examples.

### Future extensions

Several potential extensions are not implemented at this time:

* Glob patterns: like `include = "config.d/*.toml"` — rust-lang#9306
* Conditional include: conditions like gitconfig's `includeIf` —
  rust-lang#7723 (comment)
* Variable substitution and template: placeholders like `{CONFIG_DIR}`
  or `{CARGO_HOME}` — rust-lang#15769
* Implicit-include: like `.cargo/config.user.toml` or `.cargo/config.d`
  for config fragments — [#t-cargo > Built-in
  &rust-lang#96;.cargo/config.local.toml&rust-lang#96;for non-committed
  config](https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/Built-in.20.60.2Ecargo.2Fconfig.2Elocal.2Etoml.60for.20non-committed.20config/with/558705263)
* Environment variable include support: like
  `CARGO_INCLUDE=path/to/config.toml` —
  rust-lang#6728

See "Doors closed" for more.

## Design

### Key evolution

All significant changes occurred during the unstable period
(2019-2024) and were approved by the Cargo team.

**1. File naming restrictions** (rust-lang#12298, 2023-06-21) (rust-lang#16285,
2025-11-21)

The syntax has a couple restrictions:

* Path must end with `.toml` extension
* Path must not contain glob syntax or template braces

The team considered the restriction was reasonable. The restriction
applies to config file discovery but not to `--config` CLI arguments
which has already been stabilized.

**2. Loading precedence for arrays**

Config values in array elements are loaded left to right, with later
values taking precedence. The parent config file's values always take
precedence over included configs. This provides intuitive layering
behavior.

**3. Syntax complexity** (rust-lang#16174, 2025-10-30)

The feature started with simple string/array syntax. The team debated
and decided to add table syntax before stabilization to allow future
extensions.

**4. Optional includes by default vs. explicit** (rust-lang#16180, 2025-10-31)

Some users wanted missing files to be silently ignored by default for
local customization workflows. Others wanted errors to catch typos.
The team chose to error by default but added an explicit `optional =
true` field, requiring users to be intentional about optional
behavior.

### Nightly extensions

No nightly-only extensions remain. The feature is fully stabilized as
implemented.

### Doors closed

**This stabilization commits to**:

1. Supporting the `include` key in Cargo configuration
2. Relative path resolution from the including config file
3. Left-to-right merge order for arrays
4. Parent config taking precedence over includes
5. The `path` and `optional` fields in table syntax

**This does NOT prevent**:

- Adding glob/wildcard support
- Adding conditional includes
- Adding variable substitution and template

**This MAY prevent**:

* Adding new implicit-include for user local config or config
  fragments directory

As we are going to allow all file paths. Adding any implicit includes
after stabilization might break the merge precedence if people already
include those paths.

The only possible way to support it is accepting `.cargo/config.toml/`
as a directory and treat it as a config fragments directory.
`.cargo/config.toml` (and the legacy `.cargo/config`) is the only path
Cargo reserves.

## Feedback

### Call for testing

No formal "call for testing" was issued, but the feature has been
available under `-Zconfig-include` since Cargo 1.42 (2019) and has
seen real-world adoption.

### Use cases

Users reported use cases:

- **Sharing flags and environment conditionally**: [Tock
  OS](https://github.com/tock/tock),
  [esp-hal](https://github.com/esp-rs/esp-hal), rtos, and some FFI
  libraries use it for preset management across multiple board
  configurations for different hardware platforms, architectures, and
  downstream crates. A board's config (used by entering its
  directory) is defined by pulling from role-based config slices.

- **Beyond hierarchical discovery**: Some use cases require explicit
  includes because configs need to be loaded from locations outside
  the hierarchical path, or need to be conditionally included based on
  per-package or per-machine requirements that can't rely on the
  directory structure alone. This usually happens in a meta build
  system that generates configs, especially when setting `CARGO_HOME`
  to a different location off the hierarchical path.

- **User and project configuration**: Projects with checked-in configs
  (e.g., `[profile.test] debug = false` for CI) can allow developers
  to override settings locally without modifying the checked-in file.
  Developers can include an optional `.cargo/local-config.toml`
  without using git workarounds like `update-index --assume-unchanged`.

### Coverage

Test coverage is comprehensive in `tests/testsuite/config_include.rs`:

- Merge behavior: left-to-right order, hierarchy interaction
- Path handling: relative paths, different directory structures
- Cycle detection: Direct and indirect cycles
- Error cases: missing files, invalid paths, wrong extensions, missing
  required fields
- Syntax variations: string, array, inline table, array of tables
- Optional includes: missing optional files, mixed optional/required
- CLI integration: includes from `--config` arguments
- Forward compatibility: unknown table fields

### Known limitations

Issue rust-lang#15769 tracks inconsistent relative path behavior between
`include` paths (relative to config file) and other config paths like
`build.target-dir` (relative to cargo root). This is considered a
known limitation and confusion that can be addressed separately and
doesn't block stabilization.

No other known limitations blocking stabilization.

## History

- 2019-02-25: Original proposal (rust-lang#6699)
- 2019-12-19: initial implementation (rust-lang#7649)
- 2023-06-21: file extension restriction added (rust-lang#12298)
- 2025-10-30: table syntax support added (rust-lang#16174)
- 2025-10-31: optional field support added (rust-lang#16180)
- 2025-11-21: glob and template syntax restriction added (rust-lang#16285)

## Acknowledgments

Contributors to this feature:

- `@ehuss` for initial implementation and design
- `@weihanglo` for extra syntax support and enhancement
- `@rust-lang/cargo` team for the support, review and feedback
- All users providing feedback in rust-lang#7723
weihanglo added a commit to weihanglo/cargo that referenced this pull request Nov 25, 2025
# Stabilization report

## Summary

The `include` key in Cargo configuration files allows loading
additional config files, enabling better organization, sharing, and
management of Cargo configurations across projects and environments.

This feature has been available under the `-Zconfig-include` flag
since 2019 (Cargo 1.42) and has seen real-world usage.

The stabilization includes support for multiple syntax forms and the
`optional` field, which were added in October 2025 based on user
feedback.

Tracking issue: rust-lang#7723

### What is stabilized

The `include` configuration key allows loading additional config files.

**Supported syntax:**

- Array: `include = ["a.toml", "b.toml"]`
- Inline tables (preferred): `include = [{ path = "optional.toml",
  optional = true }]`
- Array of tables (not preferred): `[[include]]` with `path` and
  `optional` fields

**Key behaviors:**

- Paths are relative to the including config file and must end with
  `.toml`
- Glob syntax and templated paths (with `{}` braces} are disallowed
  in paths.
- Merge follows precedence order: included files (left-to-right) →
  parent config
- `optional = true` silently skips missing files (default: `false`)
- Cyclic includes are detected and reported as errors

See the config documentation for complete details and examples.

### Future extensions

Several potential extensions are not implemented at this time:

* Glob patterns: like `include = "config.d/*.toml"` —
  rust-lang#9306
* Conditional include: conditions like gitconfig's `includeIf` —
  rust-lang#7723 (comment)
* Variable substitution and template: placeholders like
  `{CONFIG_DIR}` or `{CARGO_HOME}` — rust-lang#15769
* Implicit-include: like `.cargo/config.user.toml` or
  `.cargo/config.d` for config fragments — [#t-cargo > Built-in
  &rust-lang#96;.cargo/config.local.toml&rust-lang#96;for non-committed config](https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/Built-in.20.60.2Ecargo.2Fconfig.2Elocal.2Etoml.60for.20non-committed.20config/with/558705263)
* Environment variable include support: like
  `CARGO_INCLUDE=path/to/config.toml` —
  rust-lang#6728

See "Doors closed" for more.

## Design

### Key evolution

All significant changes occurred during the unstable period
(2019-2024) and were approved by the Cargo team.

**1. File naming restrictions** (rust-lang#12298, 2023-06-21)
(rust-lang#16285, 2025-11-21)

The syntax has a couple restrictions:

* Path must end with `.toml` extension
* Path must not contain glob syntax or template braces

The team considered the restriction was reasonable. The restriction
applies to config file discovery but not to `--config` CLI arguments
which has already been stabilized.

**2. Loading precedence for arrays**

Config values in array elements are loaded left to right, with later
values taking precedence. The parent config file's values always take
precedence over included configs. This provides intuitive layering
behavior.

**3. Syntax complexity** (rust-lang#16174, 2025-10-30)
(rust-lang#16298 2025-11-25)

The feature started with simple string/array syntax. The team debated
and decided to add table syntax, and remove single string shorthand
before stabilization to allow future extensions and reduce complexity.

**4. Optional includes by default vs. explicit**
(rust-lang#16180, 2025-10-31)

Some users wanted missing files to be silently ignored by default for
local customization workflows. Others wanted errors to catch typos.
The team chose to error by default but added an explicit `optional =
true` field, requiring users to be intentional about optional
behavior.

### Nightly extensions

No nightly-only extensions remain. The feature is fully stabilized as
implemented.

### Doors closed

**This stabilization commits to**:

1. Supporting the `include` key in Cargo configuration
2. Relative path resolution from the including config file
3. Left-to-right merge order for arrays
4. Parent config taking precedence over includes
5. The `path` and `optional` fields in table syntax

**This does NOT prevent**:

- Adding glob/wildcard support
- Adding conditional includes
- Adding variable substitution and template

**This MAY prevent**:

* Adding new implicit-include for user local config or config
  fragments directory

As we are going to allow all file paths. Adding any implicit includes
after stabilization might break the merge precedence if people
already include those paths.

The only possible way to support it is accepting
`.cargo/config.toml/` as a directory and treat it as a config
fragments directory. `.cargo/config.toml` (and the legacy
`cargo/config/`) is the only path Cargo reserves.

## Feedback

### Call for testing

No formal "call for testing" was issued, but the feature has been
available under `-Zconfig-include` since Cargo 1.42 (2019) and has
seen real-world adoption.

### Use cases

Users reported use cases:

- **Sharing flags and environment conditionally**: [Tock
  OS](https://github.com/tock/tock),
  [esp-hal](https://github.com/esp-rs/esp-hal), rtos, and some FFI
  libraries use it for preset management across multiple board
  configurations for different hardware platforms, architectures, and
  downstream crates.  A board's config (used by entering its
  directory) is defined by pulling from role-based config slices.

- **Beyond hierarchical discovery**: Some use cases require explicit
  includes because configs need to be loaded from locations outside
  the hierarchical path, or need to be conditionally included based
  on per-package or per-machine requirements that can't rely on the
  directory structure alone. This usually happens in a meta build
  system that generates configs, especially when setting `CARGO_HOME`
  to a different location off the hierarchical path.

- **User and project configuration**: Projects with checked-in
  configs (e.g., `[profile.test] debug = false` for CI) can allow
  developers to override settings locally without modifying the
  checked-in file. Developers can include an optional
  `.cargo/local-config.toml` without using git workarounds like
  `update-index --assume-unchanged`.

### Coverage

Test coverage is comprehensive in `tests/testsuite/config_include.rs`:

- Merge behavior: left-to-right order, hierarchy interaction
- Path handling: relative paths, different directory structures
- Cycle detection: Direct and indirect cycles
- Error cases: missing files, invalid paths, wrong extensions, missing
  required fields
- Syntax variations: string, array, inline table, array of tables
- Optional includes: missing optional files, mixed optional/required
- CLI integration: includes from `--config` arguments
- Forward compatibility: unknown table fields, glob/template syntax
  restrictions

### Known limitations

Issue rust-lang#15769 tracks inconsistent relative path
behavior between `include` paths (relative to config file) and other
config paths like `build.target-dir` (relative to cargo root). This
is considered a known limitation and confusion that can be addressed
separately and doesn't block stabilization.

No other known limitations blocking stabilization.

## History

- 2019-02-25: Original proposal (rust-lang#6699)
- 2019-12-19: initial implementation (rust-lang#7649)
- 2023-06-21: file extension restriction added (rust-lang#12298)
- 2025-10-30: table syntax support added (rust-lang#16174)
- 2025-10-31: optional field support added (rust-lang#16180)
- 2025-11-21: glob and template syntax restriction added (rust-lang#16285)
- 2025-11-25: single string shorthand syntax removed (rust-lang#16298)

## Acknowledgments

Contributors to this feature:

- `@ehuss` for initial implementation and design
- `@weihanglo` for extra syntax support and enhancement
- `@rust-lang/cargo` team for the support, review and feedback
- All users providing feedback in rust-lang#7723
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-configuration Area: cargo config files and env vars Z-config-include Nightly: `include` config key

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants