CARGO-TREE(1)

πŸ“¦ version 1.76.0, in ubuntu jammy, ubuntu noble

🌳 CARGO-TREE(1) β€” the manual, but make it cute

okay bestie, welcome to cargo-tree, a General Commands Manual classic πŸ’– this is the part where we look at your dependency graph and go "oh. oh wow. that's a lot of little guys."


✨ NAME ✨

cargo-tree β€” Display a tree visualization of a dependency graph πŸ¦‹


🌸 SYNOPSIS 🌸

cargo tree [options]

that's it. that's the whole vibe. cargo tree, optionally with some flags, and suddenly your terminal is a family tree 🫢


πŸ’… DESCRIPTION πŸ’…

So like. This command prints a tree of dependencies straight to your terminal. Iconic behaviour, honestly. Here's what a lil simple project looks like when it depends on the rand package:

myproject v0.1.0 (/myproject)
`-- rand v0.7.3
    |-- getrandom v0.1.14
    |   |-- cfg-if v0.1.10
    |   `-- libc v0.2.68
    |-- libc v0.2.68 (*)
    |-- rand_chacha v0.2.2
    |   |-- ppv-lite86 v0.2.6
    |   `-- rand_core v0.5.1
    |       `-- getrandom v0.1.14 (*)
    `-- rand_core v0.5.1 (*)
[build-dependencies]
`-- cc v1.0.50

See those little (*) marks? πŸ‘€ Those packages have been β€œde-duplicated”. Translation: their dependencies were already shown somewhere else in the graph, so Cargo is NOT about to make you read the same subtree twice. It's giving efficiency. It's giving main character energy.

But bestie, if you WANT the duplicates repeated β€” if you simply must see every single node with your own two eyes β€” use the --no-dedupe option. Do it. Live your truth. πŸ’€


The -e flag is how you pick which dependency kinds get displayed. And the β€œfeatures” kind? It switches the output up entirely so you can see the features enabled by each dependency. Like, watch this β€” cargo tree -e features:

myproject v0.1.0 (/myproject)
`-- log feature "serde"
    `-- log v0.4.8
        |-- serde v1.0.106
        `-- cfg-if feature "default"
            `-- cfg-if v1.0.10

okay so read that tree with me πŸ“– in this tree, myproject depends on log with the serde feature. And then log depends on cfg-if with β€œdefault” features. Chain reaction. Slay.

And ngl, when you're using -e features, it's genuinely helpful to also use the -i flag to show how the features flow into a package. The examples below go into more detail on that β€” stay tuned, we're getting there πŸ’œ


🧚 Feature Unification 🧚

Okay this part is important, so lock in πŸ”’

This command shows you a graph that's much closer to a feature-unified graph β€” you know, the thing Cargo will actually build β€” rather than whatever you literally listed in Cargo.toml. For instance: say you specify the same dependency in both [dependencies] and [dev-dependencies], but with different features turned on. This command may merge all the features and slap a (*) on one of the dependencies to indicate the duplicate. Mystery solved, the (*) was never random ✨

So as a result:

  • for a mostly equivalent overview of what cargo build does, cargo tree -e normal,build is pretty close
  • for a mostly equivalent overview of what cargo test does, cargo tree is pretty close
🚨 BUT. And this is a big but. It doesn't guarantee the exact equivalence to what Cargo is going to build, because a compilation is complex and depends on lots of different factors. Do not come for me, I am simply relaying the facts. 😭

To learn more about feature unification, check out this dedicated section: https://doc.rust-lang.org/cargo/reference/features.html#feature-unification πŸ‘‘


more coming, bestie, don't go anywhere πŸŽ€

✨ OPTIONS ✨

okay bestie buckle UP because this is the part where we get into the flags and there are a LOT of them and every single one of them matters πŸ’…

🌳 Tree Options

  • -i spec, --invert spec β€” shows you the reverse dependencies of the package you name. Like, instead of "what does this thing need", it flips the whole tree around and shows you "who needs this thing". Inverted tree, main character energy πŸ¦‹
heads up though: inside a workspace, by default it'll only show you the package's reverse deps that live inside the tree of the workspace member sitting in your current directory. Want the whole workspace? hit it with --workspace and it'll extend out to cover the entire workspace. And if you use -p, it'll show the reverse deps only within the subtree of the package you handed to -p. iykyk πŸŽ€
  • --prune spec β€” yeets the named package right out of the dependency tree display. gone. not invited to the party πŸ™ˆ
  • --depth depth β€” sets the max display depth of the dep tree. --depth 1 = just the direct dependencies, for example. keep it shallow bestie ✨
  • --no-dedupe β€” turns OFF de-duplication of repeated dependencies. so normally when a package has already shown its deps, any further times it shows up it won't re-display them and instead slaps a (*) on there to say "yeah we've been here already". this flag makes all those dupes get repeated instead. no cap πŸ”
  • -d, --duplicates β€” only shows dependencies that come in multiple versions (and yeah, it implies --invert). when you pair it with -p, it only shows duplicates inside the subtree of the package you gave it. lowkey a lifesaver for build times and executable sizes β€” building the same package multiple times is giving wasteful πŸ’€ so this flag helps you find the offending packages, and then you can go investigate whether the package depending on the older duplicate version can be updated to the newer one so only one instance ever gets built. slay 🌸
  • -e kinds, --edges kinds β€” which dependency kinds to display. takes a comma-separated list, and here's your menu:
    • all β€” show all edge kinds.
    • normal β€” show normal dependencies.
    • build β€” show build dependencies.
    • dev β€” show development dependencies.
    • features β€” show features enabled by each dependency. and listen, if this is the only kind you give, it automatically includes the other dependency kinds too πŸͺ„
    • no-normal β€” do not include normal dependencies.
    • no-build β€” do not include build dependencies.
    • no-dev β€” do not include development dependencies.
    • no-proc-macro β€” do not include procedural macro dependencies.
⚠️ real talk: the normal, build, dev, and all dependency kinds cannot be mixed with no-normal, no-build, or no-dev dependency kinds. pick a lane bestie.

default is normal,build,dev πŸ’–

πŸŽ€ Tree Formatting Options

  • --charset charset β€” picks the character set for drawing the tree. valid values are "utf8" or "ascii". default is "utf8" ✨ (the pretty one, obviously)
  • -f format, --format format β€” sets the format string for each package. default is "{p}". it's an arbitrary string used to display each package, and these bits get swapped for the real values:
    • {p} β€” the package name.
    • {l} β€” the package license.
    • {r} β€” the package repository URL.
    • {f} β€” comma-separated list of package features that are enabled.
    • {lib} β€” the name, as used in a use statement, of the package's library.

obsessed with how customizable this is fr fr 🫢

  • --prefix prefix β€” controls how each line gets displayed. prefix can be one of:
    • indent (default) β€” shows each line indented as a tree.
    • depth β€” shows it as a list, with the numeric depth printed before each entry.
    • none β€” shows it as a flat list.

three whole vibes, pick your fave πŸ’œ

πŸ“¦ Package Selection

By default, when you don't give any package selection options, which packages get selected depends on the selected manifest file (based on the current working directory, unless --manifest-path is given). If the manifest is the root of a workspace, then the workspace's default members get selected β€” otherwise only the package defined by that manifest is selected. periodt.

The default members of a workspace can be set explicitly with the workspace.default-members key in the root manifest. And if that's not set? A virtual workspace includes all workspace members (equivalent to passing --workspace), and a non-virtual workspace includes only the root crate itself. the way it just decides for you 😭

  • -p spec…, --package spec… β€” display only the specified packages. check cargo-pkgid(1) for the SPEC format. you can pass this flag multiple times, and it supports common Unix glob patterns like *, ? and []. BUT β€” and this is the important bit β€” to stop your shell from accidentally expanding those glob patterns before Cargo ever gets to handle them, you must wrap each pattern in single quotes or double quotes. do not skip this step bestie πŸ™ˆ
  • --workspace β€” display all members in the workspace. all of them. every single one πŸ’…
  • --exclude SPEC… β€” exclude the specified packages. it must be used together with the --workspace flag. can be specified multiple times, and supports common Unix glob patterns like *, ? and []. and same warning as before: wrap each pattern in single quotes or double quotes so your shell doesn't expand it before Cargo can handle it. no cap πŸŽ€

πŸ“œ Manifest Options

  • --manifest-path path β€” path to the Cargo.toml file. by default, Cargo searches for Cargo.toml in the current directory or any parent directory. it'll go looking for you πŸ¦‹
  • --frozen, --locked β€” either one of these flags requires that the Cargo.lock file is up-to-date. if the lock file is missing, or it needs to be updated, Cargo will exit with an error. the --frozen flag also stops Cargo from trying to access the network to figure out if it's out-of-date.

these are your go-tos for environments where you want to assert that Cargo.lock is up-to-date (like a CI build) or where you want to avoid network access entirely πŸ’–

  • --offline β€” prevents Cargo from accessing the network for literally any reason. without this flag, Cargo stops with an error if it needs the network and the network isn't there. with this flag, Cargo will try to proceed without the network if it can.
⚠️ beware bestie: this may result in different dependency resolution than online mode. Cargo restricts itself to crates that are already downloaded locally, even if there might be a newer version as indicated in the local copy of the index. see the cargo-fetch(1) command to download dependencies before you go offline.

may also be specified with the net.offline config value (<https://doc.rust-lang.org/cargo/reference/config.html>). 🌸

🌟 Feature Selection

The feature flags let you control which features are enabled. when you give no feature options at all, the default feature is activated for every selected package. it's giving autopilot ✨

See the features documentation (<https://doc.rust-lang.org/cargo/reference/features.html#command-line-feature-options>) for more details.

  • -F features, --features features β€” a space- or comma-separated list of features to activate. features of workspace members can be enabled with package-name/feature-name syntax. and you can pass this flag multiple times β€” which enables all the specified features 🫢
  • --all-features β€” activate all available features of all selected packages. go big or go home πŸ‘‘
  • --no-default-features β€” do not activate the default feature of the selected packages. sometimes you just don't want the default, and that's valid πŸ’œ

πŸ–₯️ Display Options

  • -v, --verbose β€” use verbose output. you can specify it twice for "very verbose" output, which includes extra output like dependency warnings and build script output. may also be specified with the term.verbose config value (<https://doc.rust-lang.org/cargo/reference/config.html>). spill the tea β˜•
  • -q, --quiet β€” do not print cargo log messages. may also be specified with the term.quiet config value (<https://doc.rust-lang.org/cargo/reference/config.html>). silence is golden πŸŽ€
  • --color when β€” controls when colored output is used. valid values:
    • auto (default): automatically detect if color support is available on the terminal.
    • always: always display colors.
    • never: never display colors.

may also be specified with the term.color config value (<https://doc.rust-lang.org/cargo/reference/config.html>). the aesthetic matters 🌈

πŸ’« Common Options

  • +toolchain β€” if Cargo was installed with rustup, and the first argument to cargo begins with +, it gets interpreted as a rustup toolchain name (like +stable or +nightly). see the rustup documentation (<https://rust-lang.github.io/rustup/overrides.html>) for more info on how toolchain overrides work ✨
  • --config KEY=VALUE or PATH β€” overrides a Cargo configuration value. the argument should be in TOML syntax as KEY=VALUE, or given as a path to an extra configuration file. may be specified multiple times. see the command-line overrides section (<https://doc.rust-lang.org/cargo/reference/config.html#command-line-overrides>) for more info πŸ¦‹
  • -C PATH β€” changes the current working directory before running any specified operations. this affects stuff like where cargo looks by default for the project manifest (Cargo.toml), and the directories searched for discovering .cargo/config.toml, for example. this option must appear before the command name, like cargo -C path/to/my-project build.
⚠️ this option is only available on the nightly channel (<https://doc.rust-lang.org/book/appendix-07-nightly-rust.html>) and requires the -Z unstable-options flag to enable (see #10098 <https://github.com/rust-lang/cargo/issues/10098>). nightly girlies only πŸ’…
  • -h, --help β€” prints help information. your bestie when you forget everything 😭
  • -Z flag β€” unstable (nightly-only) flags to Cargo. run cargo -Z help for details. the forbidden knowledge πŸ‘‘

🌍 ENVIRONMENT

See the reference (<https://doc.rust-lang.org/cargo/reference/environment-variables.html>) for details on environment variables that Cargo reads. it's reading your env, bestie, it knows everything πŸ‘€


🚦 EXIT STATUS

  • 0: Cargo succeeded. slay πŸŽ‰
  • 101: Cargo failed to complete. we've all been there πŸ’€

EXAMPLES πŸŽ€

okay bestie, vibe check: these are the canonical ways to flex cargo tree. commands are sacred β€” copy them exactly, no cap. ✨

  1. Display the tree for the package in the current directory:
cargo tree
  1. Display all the packages that depend on the syn package:
cargo tree -i syn
  1. Show the features enabled on each package:
cargo tree --format "{p} {f}"
  1. Show all packages that are built multiple times. This can happen if multiple semver-incompatible versions appear in the tree (like 1.0.0 and 2.0.0).
cargo tree -d
  1. Explain why features are enabled for the syn package:
cargo tree -e features -i syn

The -e features flag is used to show features. The -i flag is used to invert the graph so that it displays the packages that depend on syn. An example of what this would display:

syn v1.0.17
|-- syn feature "clone-impls"
|   `-- syn feature "default"
|       `-- rustversion v1.0.2
|           `-- rustversion feature "default"
|               `-- myproject v0.1.0 (/myproject)
|                   `-- myproject feature "default" (command-line)
|-- syn feature "default" (*)
|-- syn feature "derive"
|   `-- syn feature "default" (*)
|-- syn feature "full"
|   `-- rustversion v1.0.2 (*)
|-- syn feature "parsing"
|   `-- syn feature "default" (*)
|-- syn feature "printing"
|   `-- syn feature "default" (*)
|-- syn feature "proc-macro"
|   `-- syn feature "default" (*)
`-- syn feature "quote"
    |-- syn feature "printing" (*)
    `-- syn feature "proc-macro" (*)

To read this graph, you can follow the chain for each feature from the root to see why it is included. For example, the β€œfull” feature is added by the rustversion crate which is included from myproject (with the default features), and myproject is the package selected on the command-line. All of the other syn features are added by the β€œdefault” feature (β€œquote” is added by β€œprinting” and β€œproc-macro”, both of which are default features).

If you’re having difficulty cross-referencing the de-duplicated (*) entries, try with the --no-dedupe flag to get the full output.


SEE ALSO πŸ’–

go read those too, they’re the besties of this page. 🫢


later, bestie πŸ’… β€” that’s a wrap on CARGO-TREE(1), and the source/version and date are chilling in the footer like the main characters they are. I’m not copy-pasting that line, but you know exactly where to find it. mwah πŸ’–βœ¨

πŸ“¦ where this page comes from