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] (*)