Feature flags in Cargo allow you to conditionally compile code based on specific configurations defined in your Cargo.toml, enabling you to include optional dependencies, enable debug tools, or target different environments without cluttering your main codebase. You define these features in the [features] section of your manifest and activate them during compilation using the --features flag or environment variables.
To implement this, add a [features] section to your Cargo.toml. You can define simple boolean flags, group multiple flags together, or automatically enable optional dependencies when a feature is active. For example, if you want to enable a "logging" feature that pulls in the log crate only when needed, you would configure it like this:
# Cargo.toml
[dependencies]
log = { version = "0.4", optional = true }
[features]
default = []
logging = ["log"]
In your Rust source code, you use the #[cfg(feature = "...")] attribute to wrap code blocks or entire modules that should only compile when the feature is enabled. This ensures that if the feature is off, the compiler completely ignores that code, keeping your binary size small and avoiding unused dependency warnings.
// src/main.rs
#[cfg(feature = "logging")]
use log::info;
fn main() {
#[cfg(feature = "logging")]
info!("Logging is enabled");
#[cfg(not(feature = "logging"))]
println!("Logging is disabled");
}
To build or run your project with a specific feature, pass the --features flag to Cargo. You can enable multiple features by separating them with commas. If you want to enable all features defined in your project, use --all-features.
# Build with the 'logging' feature enabled
cargo build --features logging
# Run with multiple features
cargo run --features "logging,debug-mode"
# Enable all features
cargo build --all-features
You can also set the CARGO_FEATURE_<NAME> environment variable to enable features globally for your workspace, which is useful in CI/CD pipelines. For instance, setting CARGO_FEATURE_LOGGING=1 before running cargo build achieves the same result as the command-line flag. This approach keeps your build scripts clean and allows for dynamic feature toggling based on the deployment environment.