Rust Tooling and Code Quality
cargo tree
The cargo tree command visualizes the resolved dependency graph of a package or workspace as an indented tree, making it straightforward to trace why a transitive dependency is included, inspect enabled feature flags, and identify duplicate versions of the same crate.
Standard `cargo tree`: Inverted `cargo tree -i syn`:
my_app v0.1.0 syn v2.0.98
└── serde v1.0.218 └── serde_derive v1.0.218 (proc-macro)
└── serde_derive v1.0.218 └── serde v1.0.218
└── syn v2.0.98 └── my_app v0.1.0
Essential cargo tree Flags
| Flag | Short Form | Description |
|---|---|---|
cargo tree |
— | Prints the dependency tree of the current package (deduplicating already-printed subtrees with (*)). |
--invert <spec> |
-i <spec> |
Reverses the tree to show every reverse-dependency path leading from <spec> up to your root package. |
--duplicates |
-d |
Lists all crates that appear in Cargo.lock with more than one version (e.g., hashbrown v0.14 and v0.15), along with their reverse dependency trees. |
--edges <kinds> |
-e <kinds> |
Filters or expands edge types (normal, build, dev, features, no-dev, no-build). |
--depth <N> |
— | Limits the displayed tree depth (--depth 1 shows only direct dependencies). |
--format <fmt> |
-f <fmt> |
Customizes each node's output using placeholders ({p} package, {f} features, {l} license, {r} repository). |
--target <triple> |
— | Shows the dependency graph resolved for a specific target OS/architecture (or --target all). |
Diagnosing Feature Unification and Duplicate Versions
# 1. Inspect which features are enabled on every crate in the dependency graph
cargo tree -e features
# 2. Trace why a specific feature (`serde/derive`) is enabled
cargo tree -e features -i serde/derive
# 3. Audit licenses across all non-dev dependencies
cargo tree -e no-dev --format "{p} [{l}]"
my_app v0.1.0 (/Users/dev/my_app) [MIT OR Apache-2.0]
├── bytes v1.9.0 [MIT]
└── serde v1.0.218 [MIT OR Apache-2.0]
└── serde_derive v1.0.218 (proc-macro) [MIT OR Apache-2.0]
Note the (*) marker in cargo tree output: when the same crate and version appears multiple times in the tree, cargo tree expands its children the first time and appends (*) on subsequent occurrences to keep the output compact. Pass --prefix depth or --no-dedupe when feeding cargo tree output into automated scripts.
fn format_tree_node(pkg: &str, version: &str, license: &str, deduped: bool) -> String {
let suffix = if deduped { " (*)" } else { "" };
format!("{pkg} v{version} [{license}]{suffix}")
}
fn main() {
println!("{}", format_tree_node("serde", "1.0.218", "MIT OR Apache-2.0", false));
println!("{}", format_tree_node("syn", "2.0.98", "MIT OR Apache-2.0", true));
}
serde v1.0.218 [MIT OR Apache-2.0]
syn v2.0.98 [MIT OR Apache-2.0] (*)