Cargo and Package Management
Optional Dependencies
An optional dependency (optional = true in [dependencies]) is an external crate that is only downloaded, compiled, and linked when a corresponding Cargo feature is enabled. Using optional dependencies keeps default compile times fast for users who do not need optional integrations such as serde serialization, database drivers, or compression codecs.
[dependencies]
serde = { version = "1.0", optional = true }
lz4_flex = { version = "0.11", optional = true }
[features]
serde = ["dep:serde"] <-- Explicit `dep:` syntax (Rust 1.60+ / 2024)
compression = ["dep:lz4_flex"]
Explicit dep:<crate> Syntax vs Implicit Feature Names
When you mark a dependency optional = true:
- Implicit behavior: If you do not mention
dep:<crate>anywhere inside[features], Cargo implicitly creates a feature with the exact same name as the dependency (serde). - Explicit
dep:<crate>syntax (Recommended): Writingserde = ["dep:serde"]orcompression = ["dep:lz4_flex"]inside[features]explicitly binds the feature name to the optional dependency and suppresses the implicitlz4_flexfeature name, preventing internal crate names from leaking as public feature flags!
Enabling Downstream Dependency Features (crate?/feature)
Often, enabling a feature on your crate should also enable a corresponding feature on an optional or required dependency:
"serde/derive": Enables thederivefeature onserdeand activatesserdeif it is optional."serde?/std"(Weak dependency feature): Enables thestdfeature onserdeonly ifserdeis already enabled elsewhere, without forcingserdeto be compiled on its own!
[package]
name = "event_bus"
version = "0.2.0"
edition = "2024"
[dependencies]
serde = { version = "1.0", default-features = false, optional = true }
tracing = { version = "0.1", default-features = false, optional = true }
[features]
default = ["std"]
# Weak `?/std` syntax: if `serde` or `tracing` is enabled, also enable their `std` feature,
# without pulling in `serde` or `tracing` when only `std` is enabled!
std = ["serde?/std", "tracing?/std"]
serde = ["dep:serde", "serde/derive"]
observability = ["dep:tracing"]
Conditionally Implementing External Traits
In Rust source code, guard optional dependency imports and impl blocks with the feature flag:
#[derive(Debug, PartialEq, Eq)]
pub struct EventId(pub u64);
// When `--features serde` is enabled, this conditional module or impl is compiled:
#[cfg(feature = "serde")]
mod serde_support {
// use serde::{Serialize, Deserialize};
}
impl EventId {
pub fn to_wire_string(&self) -> String {
format!("evt_{:016x}", self.0)
}
}
fn main() {
let evt = EventId(255);
println!("Wire representation: {}", evt.to_wire_string());
}
Wire representation: evt_00000000000000ff
Syntax in [features] |
Effect |
|---|---|
foo = ["dep:bar"] |
Enables optional dependency bar when feature foo is active, without exposing bar as its own feature flag. |
foo = ["bar/derive"] |
Enables optional dependency bar and turns on bar's derive feature. |
std = ["bar?/std"] |
Turns on bar's std feature only if bar is already enabled by another feature. |