Shaping the feature matrix#
By default the matrix is the powerset of a package’s features. These keys, all under [package.metadata.cargo-fc], change what gets generated.
At a glance#
| Key | Effect |
|---|---|
exclude_features | Remove features from the varied set. |
only_features | Restrict the varied set to an allowlist. |
include_features | Add features to every generated combination. |
exclude_feature_sets | Drop specific combinations (e.g. incompatible pairs). |
include_feature_sets | Always add specific exact combinations. |
allow_feature_sets | Replace the powerset with an exact list of sets. |
isolated_feature_sets | Build independent sub-matrices and merge them. |
skip_optional_dependencies | Ignore implicit optional-dependency features. |
no_empty_feature_set | Never include the empty (no-features) combination. |
max_combinations | Raise the safety limit on generated combinations. |
matrix | Attach custom metadata to cargo fc matrix rows. |
exclude_features#
Features listed here are not varied in the matrix.
exclude_features = ["default", "full"]A common use is dropping default (it’s implied by an empty --features anyway) and any umbrella full feature.
only_features#
Restrict the combinatorial matrix to an allowlist. When set, features not listed are ignored. When empty, all features are considered.
only_features = ["core", "cli"]include_features#
Add features to every generated combination. This does not restrict which features are varied — it pins features that must always be on. To restrict the varied set, use only_features.
include_features = ["feature-that-must-always-be-set"]exclude_feature_sets#
Drop groupings of features that are incompatible or don’t make sense together. Any generated combination that is a superset of a listed set is removed.
# `native-tls` and `rustls` are two TLS backends — enabling both makes no sense.
exclude_feature_sets = [["native-tls", "rustls"]]To exclude only the empty feature set, list it explicitly (or use no_empty_feature_set):
exclude_feature_sets = [[]]include_feature_sets#
Always add these exact combinations to the final matrix, unless one is already present. Non-existent features are ignored; other configuration is not applied to them.
# The exact stack you ship — always kept in the matrix, even if other rules
# (or pruning) would otherwise drop it.
include_feature_sets = [
["postgres", "rustls", "runtime-tokio"],
]allow_feature_sets#
When non-empty, the matrix becomes exactly the listed sets — no powerset is generated. Non-existent features are dropped.
allow_feature_sets = [
["hydrate"],
["ssr"],
]This is the most direct way to say “only ever test these specific configurations.”
isolated_feature_sets#
For a crate whose features fall into independent groups that never interact. Instead of one powerset over all features, cargo fc builds a sub-matrix per group and merges them (a combination appearing in more than one group is kept once).
For example, a serialization crate that supports several formats and, independently, several compression codecs. The two axes are orthogonal — the format code doesn’t care which codec is enabled — so cross-testing every format subset against every codec subset adds no coverage:
isolated_feature_sets = [
["json", "yaml", "msgpack"], # formats
["gzip", "zstd", "brotli"], # compression codecs
]The full powerset here is 2⁶ = 64 combinations; the isolated sets reduce it to 2³ + 2³ − 1 = 15 (the shared empty set is merged). Other configuration options are still respected. See Large feature sets.
skip_optional_dependencies#
Cargo generates an implicit feature for each optional dependency (e.g. an optional serde dependency yields an implicit serde = ["dep:serde"] feature). Enabling this removes those implicit features from the matrix, mirroring the flag of the same name in cargo-all-features.
skip_optional_dependencies = trueUseful when optional dependencies would otherwise blow up the matrix. See Optional dependencies.
no_empty_feature_set#
Never include the empty combination (no --features), even if it would otherwise be generated.
no_empty_feature_set = truemax_combinations#
cargo fc fails if it would generate more than a safety limit (default 100000) of combinations. Raise it when you legitimately need more:
max_combinations = 250000matrix#
Attach custom metadata to every row a package emits in cargo fc matrix. See The matrix subcommand.
matrix = { kind = "ci" }[package.metadata.cargo-fc.matrix]
requires-gpu = falseAutomatic pruning#
Some features imply others. When a full feature enables both json and yaml, a combination like {full, json} resolves — after Cargo’s feature unification — to the same effective set as {full} alone. cargo fc drops the redundant combination automatically, so it isn’t checked twice.
[package]
name = "app"
version.workspace = true
edition.workspace = true
publish.workspace = true
[features]
# `full` implies both `json` and `yaml`, so combinations like `[full, json]`
# resolve to the same effective feature set as `[full]` alone and get pruned.
json = []
yaml = []
full = ["json", "yaml"]Pruning is on by default and needs no configuration — whatever your features, the smaller equivalent combination is kept and the redundant supersets are dropped. --show-pruned reveals what was dropped and why (the SKIP rows are each equivalent to [full]):
$ cargo fc --summary-only --show-pruned check --workspace Checking [1/5] app ( features = [] ) Checking [2/5] app ( features = [full] ) Checking [3/5] app ( features = [json] ) Checking [4/5] app ( features = [json, yaml] ) Checking [5/5] app ( features = [yaml] ) Finished 5 of 8 feature combinations for 1 package in 0.00s (3 pruned) PASS app ( 0 errors, 0 warnings, features = [] ) PASS app ( 0 errors, 0 warnings, features = [full] ) SKIP app ( 0 errors, 0 warnings, features = [full, json] ) ← equivalent to [full] SKIP app ( 0 errors, 0 warnings, features = [full, json, yaml] ) ← equivalent to [full] SKIP app ( 0 errors, 0 warnings, features = [full, yaml] ) ← equivalent to [full] PASS app ( 0 errors, 0 warnings, features = [json] ) PASS app ( 0 errors, 0 warnings, features = [json, yaml] ) PASS app ( 0 errors, 0 warnings, features = [yaml] )
You should not need to change this, but you can turn it off to check every generated combination regardless of unification — with --no-prune-implied for one run, or in config:
[workspace.metadata.cargo-fc]
prune_implied = falseSee also --show-pruned and --no-prune-implied.
All of these keys can be refined per target and per command using the same patch syntax. That’s the override model.