cargo icon indicating copy to clipboard operation
cargo copied to clipboard

feat: stabilize `-Zconfig-include`

Open weihanglo opened this issue 3 weeks ago • 15 comments

FCP: https://github.com/rust-lang/cargo/pull/16284#issuecomment-3563644951

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/cargo#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/cargo#9306
  • Conditional include: conditions like gitconfig's includeIf — https://github.com/rust-lang/cargo/issues/7723#issuecomment-2386278512
  • Variable substitution and template: placeholders like {CONFIG_DIR} or {CARGO_HOME} — rust-lang/cargo#15769
  • Implicit-include: like .cargo/config.user.toml or .cargo/config.d for config fragments — #t-cargo > Built-in `.cargo/config.local.toml`for non-committed config
  • Environment variable include support: like CARGO_INCLUDE=path/to/config.toml — https://github.com/rust-lang/cargo/issues/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/cargo#12298, 2023-06-21) (rust-lang/cargo#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/cargo#16174, 2025-10-30) (rust-lang/cargo#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/cargo#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, 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/cargo#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/cargo#6699)
  • 2019-12-19: initial implementation (rust-lang/cargo#7649)
  • 2023-06-21: file extension restriction added (rust-lang/cargo#12298)
  • 2025-10-30: table syntax support added (rust-lang/cargo#16174)
  • 2025-10-31: optional field support added (rust-lang/cargo#16180)
  • 2025-11-21: glob and template syntax restriction added (rust-lang/cargo#16285)
  • 2025-11-25: single string shorthand syntax removed (rust-lang/cargo#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/cargo#7723

weihanglo avatar Nov 21 '25 15:11 weihanglo

r? @epage

rustbot has assigned @epage. 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

rustbot avatar Nov 21 '25 15:11 rustbot

@rustbot fcp merge

weihanglo avatar Nov 21 '25 15:11 weihanglo

@rfcbot fcp merge

weihanglo avatar Nov 21 '25 15:11 weihanglo

Error encounted: Provided team `` is invalid

rust-rfcbot avatar Nov 21 '25 15:11 rust-rfcbot

@rfcbot fcp merge t-cargo

weihanglo avatar Nov 21 '25 15:11 weihanglo

Error encounted: Provided team t-cargo is invalid

rust-rfcbot avatar Nov 21 '25 15:11 rust-rfcbot

@rfcbot fcp merge T-cargo

weihanglo avatar Nov 21 '25 15:11 weihanglo

Team member @weihanglo has proposed to merge this. The next step is review by the rest of the tagged team members:

  • [x] @0xPoe
  • [x] @Eh2406
  • [x] @Muscraft
  • [x] @arlosi
  • [ ] @ehuss
  • [x] @epage
  • [ ] @joshtriplett
  • [x] @weihanglo

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

rust-rfcbot avatar Nov 21 '25 15:11 rust-rfcbot

Disclosure: This is an AI assisted stabilization report. I (@weihanglo) have reviewed and revised it (quite a lot?) so the full responsibility of it is on me.

weihanglo avatar Nov 21 '25 16:11 weihanglo

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

rustbot avatar Nov 21 '25 21:11 rustbot

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

rustbot avatar Nov 24 '25 16:11 rustbot

:umbrella: The latest upstream changes (possibly dce5a6b8f5c70f8216a73b13cecd4211e81ac79b) made this pull request unmergeable. Please resolve the merge conflicts.

rustbot avatar Nov 25 '25 17:11 rustbot

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

rustbot avatar Nov 25 '25 20:11 rustbot

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

rustbot avatar Nov 30 '25 20:11 rustbot

:bell: This is now entering its final comment period, as per the review above. :bell:

rust-rfcbot avatar Dec 02 '25 16:12 rust-rfcbot

:umbrella: The latest upstream changes (possibly 1d3fb78257c97258d6ae6368859e36495fb33c8e) made this pull request unmergeable. Please resolve the merge conflicts.

rustbot avatar Dec 04 '25 15:12 rustbot

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

rustbot avatar Dec 04 '25 17:12 rustbot

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

rustbot avatar Dec 05 '25 21:12 rustbot

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

rustbot avatar Dec 11 '25 21:12 rustbot

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

rust-rfcbot avatar Dec 12 '25 16:12 rust-rfcbot

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

rustbot avatar Dec 12 '25 18:12 rustbot