# pipdeptree: reading the dependency tree of an installed Python environment

> pipdeptree turns the flat output of pip freeze into a parent-child tree, flags version conflicts and cycles, and ships a Rust core behind a Python entry point. It is a diagnostic tool, not a resolver.

**tox-dev/pipdeptree** — A command line utility to display dependency tree of the installed Python packages.

- Repository: https://github.com/tox-dev/pipdeptree
- Website: https://pipdeptree.readthedocs.io
- Stars: 3,025 · Forks: 161
- Language: Rust
- License: MIT
- Published: 2026-08-04 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/tox-dev-pipdeptree

## What pipdeptree answers that pip freeze cannot

pip freeze prints one line per installed distribution, in a flat alphabetical list. That list tells you what is present, not why. The README states the difference directly: pipdeptree adds parent-child relationships and reports dependency conflicts or cycles. The practical question it answers is the one that shows up when a transitive package breaks: which installed distribution declared this requirement, and does the installed version satisfy it. The rendered tree marks each edge with a check or a warning and prints both the required range and the installed version, so a line like a warning next to MarkupSafe required: >=0.23 installed: 0.22 is readable without any further lookup. The audience is narrow and concrete: developers debugging a virtualenv they did not build by hand, release engineers checking a container image before it ships, and anyone who has to explain to a colleague why a package is in the environment at all.

## The Rust core, the Python entry point, and what runs where

The repository layout is unusual for a tool that installs from PyPI as a pure command line utility. Cargo.toml defines a crate named pipdeptree whose lib target is _pipdeptree, built with pyo3 and crate-type cdylib plus rlib. The Python package is built with meson-python, and pyproject.toml declares the console script as pipdeptree = pipdeptree._runner:main. So the binary you invoke is a thin Python entry point over a compiled extension. The crate description in Cargo.toml says the build resolves the release version and that the crate is never published to crates.io, which explains the placeholder version 0.0.0 in the manifest. The dependency list is the interesting part: clap for argument parsing, serde_json with the preserve_order feature for output, pep508_rs for requirement parsing, rayon for parallelism, and rustc-hash. That combination suggests parsing and rendering happen in Rust while the interpreter supplies the installed distribution metadata. The manifest also sets unsafe_code = "forbid" and turns on clippy pedantic and nursery lints, which is a stricter posture than most Python tooling takes. The Python side requires 3.10 or newer and depends on nab, nab-index and nab-project.

## Installing pipdeptree and reading your first tree

The README gives the install as a single pip command, then running the bare command with no arguments prints the tree for the current environment. Because the package ships a compiled extension, the install needs a wheel matching your interpreter; on platforms without one, pip has to build from source with meson, ninja and a Rust toolchain present, since build-system requires meson>=1.12, meson-python>=0.21 and ninja>=1.13.2, and rust-toolchain.toml pins the compiler. The two commands below are the whole quick start.

```bash
pip install pipdeptree
pipdeptree
```

The output is an indented tree with box-drawing characters, one block per top-level distribution, each child line showing the requirement range and the installed version. From there, the reverse view is the one most people actually need: it answers which parents depend on a given package rather than what a package depends on.

```bash
pipdeptree --reverse --packages markupsafe
```

For machine consumption, the renderer is selected with -o. The README lists JSON, Mermaid and Graphviz, and shows redirecting the Graphviz SVG output to a file. The same render flags also apply to --summary, which reports package counts, depth, conflicts, cycles, licenses and size in aligned text, a styled table via -o rich, or JSON.

## Inspecting a tree you have not installed: from-index and from-lock

Two subcommands extend the tool beyond the current environment. from-index resolves requirements against a package index, and the README notes i is a shorthand alias; it accepts either a bare package name or a requirements file. from-lock reads a resolved PEP 751 lock offline, with l as the shorthand alias. Both accept the same render flags as the plain invocation, including --summary. This is the part of the tool that is easiest to misread. from-index is described as resolving requirements against a package index, which means the answer depends on what the index returns at that moment and on the resolver's choices, not on what is installed locally. from-lock does the opposite: it reads a file that already records a resolution and does not need network access. If you want a reproducible picture, the lock path is the one to use, because the file is the input rather than a live index.

## Where pipdeptree stops being the right tool

pipdeptree reads state; it does not change it. There is no install, uninstall or upgrade subcommand in the README, and no dependency resolution step that would let it decide what to install. If your problem is that two packages demand incompatible ranges of a third, pipdeptree will show you the conflict clearly, and then you still need pip, uv, Poetry or conda to act on it. A second boundary is the environment it inspects. It reads installed distribution metadata, so it describes the interpreter it runs under: run it inside the virtualenv you care about, not against a global Python, or you will get a tree for the wrong set of packages. A third is documentation depth. The README covers the flags and the subcommands but does not document rollback, exit code semantics for the conflict report, or whether the conflict warnings affect the process exit status. If you plan to gate a pipeline on conflicts, that gap matters and you should confirm the behaviour yourself rather than assume it.

## pipdeptree against pip check and pip show

The closest built-in alternative is pip check, which reports broken requirements in the environment. The difference is scope and shape: pip check gives you a list of unsatisfied requirements, while pipdeptree gives you the graph those requirements live in, so you can see the parent that introduced the constraint and trace a conflict back to its source rather than only seeing its symptom. pip show answers a different question again, describing one distribution's metadata including its Requires field, one package at a time. There is no tree, no reverse lookup across the whole environment, and no aggregate summary. For a single package, pip show is faster and always available. For the question of why a package is installed and what else depends on it, the tree is the only one of the three that answers directly. The reverse mode and the summary mode are the two features with no equivalent in the standard tooling.

## Maintenance, licensing and the upgrade surface

The repository is not archived, and the last push was on 2026-08-26, with releases 4.2.0 on 2026-07-31, 4.2.1 on 2026-08-15 and 4.2.2 on 2026-08-26. The project is MIT licensed, and pyproject.toml declares license = "MIT" with license-files pointing at LICENSE, so redistribution and modification are permitted under the usual MIT terms; that is a statement about the licence text, not legal advice. The upgrade cost is mostly about output stability. The tool has moved to a Rust core with a Python entry point, and the renderers now share flags across the plain tree, the subcommands and --summary. If you parse -o json in a script, pin the version and re-check the emitted keys on upgrade rather than assuming the schema is frozen across minor releases. The Python floor is 3.10, and the crate requires Rust 1.85, which only matters if you build from source.

## Conclusion

Adopt pipdeptree if you need to explain what is actually inside an existing virtualenv: which parent pulled in a package, which requirement is unsatisfied, whether the graph has a cycle. Do not adopt it as a dependency resolver or as a lock file generator; the README describes it as a display utility, and resolving is delegated to the from-index subcommand against a package index. Before relying on it in CI, verify two things on your own interpreter: that the wheel for your Python version installs cleanly given the Rust extension, and that the JSON schema emitted by -o json matches the keys your scripts parse, since the project has moved to a Rust core and the output surface is now shared across several renderers.

## FAQ

### How do I install pipdeptree?

The README gives pip install pipdeptree as the install command. Because the package ships a compiled Rust extension, a matching wheel is the smooth path; otherwise pip builds from source with meson, ninja and a Rust toolchain.

### How do I use pipdeptree?

Run pipdeptree with no arguments to print the dependency tree of the current environment. Add --reverse --packages <name> to see which packages require a given one, or -o json, -o mermaid or -o graphviz-svg to change the output format.

### How do I use pipdeptree in Python?

pyproject.toml declares the console script as pipdeptree = pipdeptree._runner:main, so the documented interface is the command line rather than an importable API. The README shows no Python-level usage example.

### What is a pip dependency?

A dependency is a distribution that another installed distribution declares it needs, with a version range. pipdeptree renders those declarations as parent-child edges and marks each one as satisfied or unmet.

### How do I check my pip list?

pip freeze prints the flat list of installed distributions, which is what pipdeptree starts from. pipdeptree adds the parent-child relationships on top, so you can see why each entry is there.

## Sources

- [Official documentation](https://pipdeptree.readthedocs.io)
- [Official README](https://github.com/tox-dev/pipdeptree#readme)
- [Project repository](https://github.com/tox-dev/pipdeptree)
- [Release notes](https://github.com/tox-dev/pipdeptree/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tox-dev-pipdeptree
