# leaves: a text-mode disk usage treemap for remote shells

> leaves renders a WinDirStat-style treemap of files and directories as nested rectangles in a terminal, so you can find what is eating disk space over SSH. It builds with cargo, defaults to a depth of 5, and honours .gitignore.

**patonw/leaves** — A text-mode disk usage visualization utility

- Repository: https://github.com/patonw/leaves
- Stars: 402 · Forks: 9
- Language: Rust
- License: MPL-2.0
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/patonw-leaves

## The problem leaves solves, and who ends up using it

Disk usage tools split into two camps. du and ncdu give you numbers and a sorted list. QDirStat and WinDirStat give you a picture, where a rectangle's area maps to a file's size, so a 200 MB file is twice the area of a 100 MB sibling. The picture is faster to read than a list when you do not yet know what you are looking for.

The catch is that graphical tools need a graphical session. On a headless server, a container, or a jump host, you are working over a remote shell and there is no display to draw into. leaves exists for that gap. The README is explicit about the trade: "due to the limited resolution of working at a character level, this is a fairly coarse approximation compared to a graphical tool. On the other hand, this will work over remote shell connections when graphical desktop environments are not available or impractical."

So the audience is narrow and specific. It is the engineer who is already comfortable in a terminal, who wants a spatial view rather than a sorted list, and who is willing to accept that a rectangle drawn in character cells cannot be as precise as one drawn in pixels. If you want a number you can paste into a ticket, du is still the right tool. If you want to see the shape of a directory tree at a glance, that is the use case leaves is built for.

## How the treemap is drawn and why depth is capped at 5

leaves scans the target directory, then enters a full-screen view built on ratatui. The screen has three regions. A title bar shows the path of the current view with its total size and file count. A sidebar holds a collapsible explorer tree, with a details box underneath it for the selected item. The central panel is the treemap itself.

Each file or directory becomes a rectangle whose area is roughly proportional to its disk size. The word roughly does real work here. The README states that each border takes two characters wide and tall at minimum, so deeply nested items appear smaller than a top-level item of the same size. The nesting is bounded by --max-depth, which defaults to 5 and is described in --help as the maximum depth of tree to keep in memory. Subtrees below that depth are replaced with summary nodes, and the flag does not affect scan depth. That distinction matters: leaves still walks the whole tree, it just stops keeping the deep structure in memory and collapses it into summaries.

Colour carries meaning. Files are coloured by extension using a yellow, orange and brown scheme; directories are coloured by name using a cooler viridis palette of blues and greens. The README gives the reason: colouring directories by name lets you compare subdirectories across a hierarchy, so debug versus release or src versus test stand out, and colouring files by extension makes .lock or .json files visible across directories. The two palettes are swapped with the LEAVES_COLORS=swap environment variable, which is worth knowing because the README notes both palettes overlap on yellow.

## Install and first run: cargo build, then a scan of one directory

The README points first at the releases page, where pre-built binaries exist for a select number of platforms. If there is no binary for your system, you build from source, which needs a Rust toolchain. The README gives rustup as the standard route, and notes you will likely need curl plus basic build tools such as gcc, make and ld from your distribution's build-essentials or base-devel metapackage.

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

Nix is offered as an alternative. The repository ships default.nix, shell.nix, flake.nix and package.nix, and the README shows loading the build environment from the project directory with nix-shell after installing nix.

```bash
curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install | sh -s -- --daemon
```

With a toolchain in place, compile a release build from the project directory.

```bash
cargo build --release
```

The README also documents installing for the current user, with the caveat that your environment must be configured to find executables at the install destination.

```bash
cargo install --path .
```

To try it without installing, run from source and pass the directory as the final argument.

```bash
cargo run --release -- [option flags] DIR_TO_SCAN
```

An installed copy is invoked with the path directly. With no path, leaves scans the current directory.

```bash
leaves ~/Documents
```

What you should see is the main view: title bar at the top, explorer tree and details box on the left, treemap filling the centre, and shortcut keys along the bottom. Arrow keys move through the tree, space opens and closes a directory, Enter focuses the selected directory and Backspace goes back up. The README states that the selection is synchronised with the explorer tree in both directions, and that the mouse works in both the tree and the treemap.

## Ignore rules are on by default, and that is the sharpest edge

leaves does not scan everything by default. Hidden directories are skipped, and anything matching patterns in .gitignore or .ignore files in the hierarchy is not counted. There are separate flags to re-enable each source: -H for hidden files and folders, -I for .ignore'd files, -G for .gitignore'd files and folders, and -E for files listed in .git/info/exclude. A single -A, described in --help as "Don't *automatically* skip any files. Only overrides will be used", turns all of them off at once.

This is a sensible default for source trees, where node_modules or target would otherwise dominate the picture. It is also a trap. If you point leaves at a directory to find out what is consuming space, and the answer happens to be inside a gitignored build output directory, the default run will not show it. The size in the title bar will not match du. That is not a bug, but it is the kind of mismatch that sends people looking for one. When the numbers disagree with du, reach for -A before anything else.

The override mechanism is the other half of this. Positional arguments after the path are git-style override globs, and a glob prefixed with ! negates. The README says you can pass globs or negations to refine the selection. Combined with -A, this gives a way to include everything except one noisy subtree, or to include only one ignored directory.

## Deflate, expand, and the boundary you cannot cross

The README is candid that showing millions of files across thousands of directories is not useful. With a handful of characters per file, little information survives. leaves handles this with summaries: directories below a certain depth group files of the same extension into a single rectangle sized to their cumulative total.

That depth is not fixed after launch. The selected directory can be expanded or deflated at runtime with the e and d keys. Deflating replaces a directory's child rectangles with file type summaries. Expanding rescans that directory and its children up to the current runtime depth, with anything beyond it grouped into summary nodes again. The runtime depth itself is adjusted with the + and - keys. So there are two depth controls with different lifetimes: --max-depth at launch, and the + / - keys during a session.

There is a hard boundary in the focus view. Enter focuses the selected directory, replacing the explorer and treemap contents, and Backspace returns to the parent with the previously viewed directory selected. But the README states plainly that you cannot navigate beyond the initial target directory the application was launched with. To look at files outside the current hierarchy you quit and restart with a new target. That is a deliberate simplification, and it means leaves is not a general-purpose file browser. If your work involves jumping between unrelated parts of the filesystem, you will be restarting the program.

## How leaves differs from ncdu and QDirStat

The closest terminal comparison is ncdu. ncdu presents a sorted, navigable list of directory sizes with percentages. It is precise, it is fast, and its output is easy to act on because you are reading numbers. leaves presents a treemap. The difference is not cosmetic: a sorted list answers "what is biggest here", while a treemap answers "what does the distribution look like", which is a different question. You can spot a directory that is large only because of one file, or a directory that is large because of ten thousand small ones, from the shape of the rectangles. In a list, both look like a big number.

The cost of that is precision. leaves itself says the character-level rendering is a coarse approximation, and the two-character minimum border means nesting distorts apparent sizes. ncdu has no such distortion. If you need to report an exact figure, take it from du or ncdu and use leaves to decide where to look.

Against QDirStat, the difference is the environment rather than the idea. QDirStat is a graphical tool and leaves is explicitly positioned as the option for when a graphical desktop is not available or impractical. The two are not really competitors; they are the same idea for two different settings. If you have a display, the graphical tool will render more accurately. If you do not, leaves is the version that works.

## Licence, maintenance and what upgrading costs

leaves is licensed under MPL-2.0. That is a file-level copyleft licence: modifications to files already covered by the licence stay under it, while larger works that combine leaves with other code can be distributed under other terms. The practical consequence for most users is that running the binary or depending on it is unencumbered. If you intend to fork and ship modified source, read the licence text in the LICENSE file rather than a summary, and treat this paragraph as a pointer, not as legal advice.

The repository is not archived, and the last push was on 2026-07-28. That is recent enough that the project is not dormant, but the release history is short: v0.1.1 on 2026-07-07, v0.2.0 on 2026-07-10, and v0.2.0-cross on 2026-07-15. Three releases inside nine days, then no further release through the last push. The Cargo.toml declares version 0.2.0 and edition 2024, so the toolchain requirement is a recent Rust.

Upgrade cost is low in the ordinary case. The dependency list is all crates.io packages, with ratatui and crossterm doing the terminal work, ignore handling gitignore semantics, and clap parsing arguments. There is no daemon, no database, no server component, and no configuration file documented in the README. The one build-time choice is the clipboard feature, which is on by default and pulls in arboard; the Cargo.toml shows it can be disabled since arboard is an optional dependency behind the clipboard feature. If arboard's Wayland-related dependencies cause trouble on your platform, that is the knob to turn.

## Conclusion

Adopt leaves if you regularly hunt for large files on machines you only reach through a terminal, and if you already have a Rust toolchain or can use a pre-built binary from the releases page. Skip it if you need exact byte-level accounting, if you want to walk outside the directory you launched it on, or if a graphical tool such as QDirStat is available on the same machine, since leaves itself notes that character-cell borders make it a coarse approximation. Before relying on it, run it once against a directory whose contents you already know and check two things: that the ignore rules it applies by default match what you expect (use -A to see everything), and that the --max-depth default of 5 does not hide the subtree you actually care about.

## FAQ

### How do I install leaves?

Download a pre-built binary from the releases page if one exists for your platform. Otherwise install a Rust toolchain, then run cargo build --release in the project directory, or cargo install --path . to install it for the current user. Nix users can load the build environment with nix-shell, since the repository includes default.nix and flake.nix.

### Why does leaves report a smaller total than du?

By default leaves skips hidden directories and anything matching .gitignore or .ignore patterns in the hierarchy, so ignored build output and similar files are not counted. Pass -A to stop skipping automatically, or use the individual -H, -I, -G and -E flags to re-enable specific sources.

### Can leaves navigate outside the directory it was launched on?

No. The README states that you cannot navigate beyond the initial target directory the application was launched with, and that viewing files outside the current hierarchy requires quitting and restarting with a new target.

## Sources

- [Issues](https://github.com/patonw/leaves/issues)
- [License: MPL-2.0](https://github.com/patonw/leaves/blob/main/LICENSE)
- [patonw/leaves on GitHub](https://github.com/patonw/leaves)
- [README](https://github.com/patonw/leaves/blob/main/README.md)
- [Releases](https://github.com/patonw/leaves/releases)

---

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