# lstr: a Rust directory tree viewer with a TUI mode

> lstr is a Rust rewrite of the classic tree command, adding an interactive TUI, git status columns, JSON and HTML output. It suits engineers who want a fast tree view and are willing to accept a young tool with a small surface area.

**bgreenwell/lstr** — A fast, minimalist directory tree viewer, written in Rust.

- Repository: https://github.com/bgreenwell/lstr
- Website: https://crates.io/crates/lstr
- Stars: 1,544 · Forks: 31
- Language: Rust
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/bgreenwell-lstr

## What lstr solves, and who it is for

The README describes lstr as "a fast, minimalist directory tree viewer, written in Rust", inspired by the command line program tree. The problem it addresses is narrow: you want to see the shape of a directory tree without leaving the terminal, and you want more than ls -R gives you. The classic mode prints a tree-like listing with optional file sizes, permissions, git status markers and icons. The interactive mode turns the same data into a keyboard- and mouse-driven TUI.

The target reader is an engineer who already lives in a terminal and wants a tree view that respects .gitignore, can be piped as JSON into another tool, or can be browsed interactively without running a separate file manager. The philosophy section of the README is explicit about the trade-off: essential features without the bloat, and an optional TUI rather than a TUI-first design. That means the classic mode stays scriptable, and the interactive mode is opt-in via a subcommand.

## How the classic and interactive modes share a codebase

The repository is a single Rust crate. Cargo.toml lists ratatui 0.30 as the TUI library, clap 4.6 for argument parsing, ignore 0.4.22 for gitignore-aware traversal, lscolors 0.21 for LS_COLORS handling, git2 0.21 for repository status, globset for pattern matching, natord for natural sorting, and serde_json for JSON output. That dependency set maps directly onto the feature list: traversal and filtering come from ignore, coloring from lscolors and colored, git status from git2, and the interactive view from ratatui.

The two modes are not separate binaries. The usage block shows a single entry point with an optional subcommand: lstr [OPTIONS] [PATH] for the classic view, and lstr interactive [OPTIONS] [PATH] for the TUI. Several flags are marked in the option table as classic mode only, including --hyperlinks, --file-depth, --max-items, --du and --output. That asymmetry is worth noting: if you build a script around --output json, you are on the classic path, and the interactive mode will not accept it.

Filtering is layered. The -g flag makes traversal respect .gitignore and other standard ignore files, while -L controls recursion depth and -d restricts output to directories. For crowded trees, --file-depth hides individual files below a given depth and summarizes them as [+N files], and --max-items caps entries per directory with a [+N more] summary. Both are documented as classic mode only.

## Installing lstr and running a first tree

The README gives several install paths. On macOS, Homebrew is described as the easiest. The command is a single line, and after it finishes you should have an lstr binary on your PATH.

```zsh
brew install lstr
```

On NetBSD, the project is packaged in the official repositories, and the README gives pkgin as the install command.

```bash
pkgin install lstr
```

For Arch Linux, the README points to a community-maintained lstr-git package in the AUR that builds the latest commit from the repository. It does not prescribe a specific helper, and shows paru as an example.

```bash
paru -S lstr-git
```

From source, you need the Rust toolchain. Cargo.toml sets rust-version to 1.88, so a toolchain older than that will fail to build. The README gives the clone and install steps.

```bash
git clone https://github.com/bgreenwell/lstr.git
cd lstr
cargo install --path .
```

Once installed, the simplest invocation prints a tree for the current directory, since PATH defaults to "." when omitted. Adding -g makes the walk respect your .gitignore, which is the flag most people will want inside a repository.

```bash
lstr -g
```

To see the interactive mode, run the subcommand. The README states that it supports keyboard and mouse navigation, filename search bound to /, and in-place file opening that returns to the tree when your editor exits. The --editor flag overrides $VISUAL and $EDITOR, and --expand-level sets the initial depth to expand. None of these are shown with example values in the README, so check lstr interactive --help for the exact argument forms before scripting them.

## Git status markers and what they do not tell you

The -G flag adds git status to the listing. The README states that files show statuses such as M, A and ?, and that directories reflect the status of their contents. This is the feature that most clearly separates lstr from plain tree, and it is implemented through the git2 dependency rather than by shelling out to git.

The limitation is that the README does not describe how the directory rollup behaves when a directory contains a mix of modified, added and untracked files, nor how it handles a repository with a large index. It also does not document behavior outside a git repository, though the option table treats -G as a normal flag rather than one that errors. If you plan to depend on the exact marker for a directory in a script, verify it against your own repository first. The README is silent on that detail.

## JSON and HTML output, and their boundaries

lstr can emit more than text. The --output flag accepts text (the default), json or html. The README describes the HTML variant as a self-contained directory index for browsing offline, where directories render as collapsible <details> elements and files as relative links, so the page can be saved next to the tree. The JSON variant is aimed at scripting.

Both are marked classic mode only in the option table. That is a real constraint rather than a footnote: the interactive TUI and the machine-readable formats are mutually exclusive, so a workflow that browses interactively and then exports cannot do both in one invocation. The README also does not specify the JSON schema, so anyone consuming it should inspect the output of a small directory before writing a parser against it. For HTML, the claim that the page is self-contained is the important one if you intend to ship the file to someone without the original tree alongside it.

## Where lstr is the wrong tool

The README positions lstr against tree, and the comparison cuts both ways. tree has been around far longer and handles unusual filesystems, encoding problems and deep recursion edge cases that a younger implementation may not. If your job is to enumerate a filesystem reliably in a script that runs unattended on many machines, the mature tool is the safer default, and lstr's value is concentrated in its interactive mode and its structured output.

There are also platform constraints. Permissions display via -p is documented as Unix-like systems only, so on Windows that column is not available. The --icons flag requires a Nerd Font, and the README links to the Nerd Fonts site rather than bundling glyphs, so a terminal without one will show fallback characters. The --du flag, which shows cumulative directory sizes, is described as classic mode only and implies -s, meaning a large tree pays the cost of walking every file to compute totals.

Finally, the project is small by design. The philosophy section explicitly favors essential features over breadth. If you need a file manager, a diff viewer or a search tool, lstr is not trying to be any of those, and the README does not claim otherwise.

## The alternative: plain tree, and the real difference

The obvious alternative is the tree command that inspired lstr, which the README links to as Old-Man-Programmer/tree. The difference in approach is architectural. tree is a C program that prints a listing and exits; everything you get is text on stdout, and any interactivity comes from piping that text into a pager or a fuzzy finder. lstr keeps that classic path but adds a second mode built on ratatui, where the tree is a live widget you navigate with the keyboard and mouse, search with /, and open files from in place, returning to the tree when the editor exits.

The second difference is structured output. tree has its own output options, but lstr's README specifically advertises JSON for scripting and a self-contained HTML index with collapsible <details> elements and relative links. If your workflow ends in a browser or a script, that is a meaningful gap between the two tools. If your workflow ends in a terminal reading text, the gap is much smaller, and the mature tool's edge-case handling becomes the deciding factor.

## Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-08-10, which is recent. The release history shows v0.4.0 on 2026-07-13, v0.3.0 on 2026-07-12, and v0.2.1 back on 2025-06-24. The jump from 0.2.1 to 0.3.0 and then 0.4.0 within roughly a year, with two releases a day apart, suggests the project is still settling its interface. Anyone pinning lstr in a build pipeline should treat the 0.x version numbers as a signal that flags and output formats can move.

The licence is MIT, stated in both the README badge and the Cargo.toml license field. MIT is permissive: it allows use, modification and redistribution provided the copyright notice and permission notice are retained. That is a description of the licence text, not legal advice, and the repository's LICENSE file is the authoritative copy.

The upgrade cost is mostly build-side. Cargo.toml sets rust-version to 1.88 and edition 2021, so source builds need a recent toolchain. The release profile sets strip, lto, codegen-units = 1 and panic = "abort", which trades compile time for a smaller binary. The repository also carries a flake.nix and flake.lock, a dist-workspace.toml for release binaries, a wix/ directory for Windows packaging, and a RELEASE_CHECKLIST.md, so the maintainer has a defined release path. The README does not document a rollback or downgrade procedure, which is the gap to plan around if you install from source.

## Conclusion

Adopt lstr if you want a tree-style listing with a keyboard-driven TUI, git status markers and JSON or HTML output, and you are comfortable installing from Homebrew, Cargo or pkgin. Skip it if you need a mature tool with years of edge-case handling, or if you are on a platform where none of the documented install paths apply. Before relying on it, verify that your Rust toolchain is at least 1.88 for a source build, check that --icons renders correctly in your terminal font, and confirm the JSON and HTML output formats match what your scripts expect, since both are classic-mode only. The README does not document rollback or a downgrade path, so pin a version when you install from source.

## FAQ

### How do I install lstr on macOS?

The README describes Homebrew as the easiest option and gives brew install lstr. From source, you clone the repository and run cargo install --path ., which requires the Rust toolchain.

### What is the difference between lstr and lstr interactive?

lstr with no subcommand prints a classic tree-like listing, while lstr interactive launches a TUI with keyboard and mouse navigation, filename search via /, and in-place file opening. Several flags, including --output, --du, --max-items and --file-depth, are documented as classic mode only.

### Does lstr respect .gitignore files?

Yes, when you pass the -g or --gitignore flag. The README states that it respects .gitignore and other standard ignore files. Without that flag, traversal is not filtered by ignore rules.

### What Rust version does lstr need to build from source?

Cargo.toml sets rust-version to 1.88 and edition 2021, so a source build requires a toolchain at least that new. The README's source instructions are a git clone followed by cargo install --path .

## Sources

- [bgreenwell/lstr on GitHub](https://github.com/bgreenwell/lstr)
- [License: MIT](https://github.com/bgreenwell/lstr/blob/devel/LICENSE)
- [Project website](https://crates.io/crates/lstr)
- [README](https://github.com/bgreenwell/lstr/blob/devel/README.md)
- [Releases](https://github.com/bgreenwell/lstr/releases)

---

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