lstr: a tree clone with a TUI mode and three output formats
A fast, minimalist directory tree viewer, written in Rust.
At a glance
- What is it?
- lstr is a Rust directory tree viewer that keeps the classic tree layout and adds an interactive mode, git status columns and JSON or HTML output. It is a good fit for people who live in a terminal and want a scriptable listing, but the feature set thins out fast once you leave classic mode.
- Who is it for?
- Adopt lstr if you want a tree-style listing that can also emit JSON for scripts or a self-contained HTML index, and if a keyboard-driven TUI with filename search matches how you browse a repo. Do not adopt it if you need one consistent feature set across both modes, since --du, --output, --file-depth, --max-items and --hyperlinks are documented as classic mode only.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 37 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap lstr is trying to fill
The README states the project is inspired by the command line program tree, with an interactive mode added on top. That framing matters, because the two tools are not competing on the same axis. tree prints a static structure and exits. lstr prints the same kind of structure but also ships a TUI you launch with lstr interactive, where the documentation describes keyboard and mouse navigation, filename search bound to /, and in-place file opening that returns to the tree when your editor exits. The intended user is someone who already reaches for tree, or for ls, and wants a second mode for exploration without switching to a file manager. The other half of the pitch is scripting: the README lists JSON output, a self-contained HTML directory index, and pipe-friendly text. Those are three separate audiences sharing one binary, which is the source of both the tool's appeal and most of its rough edges.
What the interactive mode actually changes
The classic invocation is lstr [OPTIONS] [PATH] and the interactive one is lstr interactive [OPTIONS] [PATH]. PATH defaults to the current directory in both cases. Two flags exist only for the interactive mode: --expand-level <LEVEL> sets the initial depth the tree is expanded to, and --editor <COMMAND> overrides $VISUAL and $EDITOR for opening files. The editor override is the detail worth noticing. It means the TUI does not guess at a launcher; it shells out to whatever command you name, and the documented behaviour is that control returns to the tree when that editor exits. If your editor is a terminal program, the return path depends on the terminal being restored correctly, which the README asserts but does not describe. The Ctrl+s file-picker mode is listed under the scriptable features rather than the TUI features, so its exact scope is not spelled out in the material available.
Icons, permissions, sizes and git status in the listing
The optional columns are where lstr departs most from tree. --icons draws file-specific glyphs and requires a Nerd Font, so it is a hard dependency on your terminal font rather than a cosmetic toggle. -p adds permissions and, on Unix-like systems only, marks symlinks and setuid, setgid and sticky bits. -s shows file sizes, while --du shows cumulative directory sizes and implies -s. -G adds git status letters such as M, A and ?, and the README states that directories reflect the status of their contents, which is the behaviour that makes the column useful at a glance rather than only at the leaf level. Coloring is not lstr's own scheme: the README says it respects LS_COLORS, so your existing file and directory colors carry over. Sorting is configurable by name, size, modification time or extension, with --dirs-first, --case-sensitive, --natural-sort, --reverse and --dotfiles-first variants. The natural-sort flag is documented as taking precedence over --case-sensitive, which is the kind of precedence rule that is easy to trip over when combining flags.
Filtering, depth control and the two summarization flags
Filtering is handled by three separate mechanisms. -g respects .gitignore and other standard ignore files. -L caps how deep the walk goes. -d drops files entirely and lists directories only. For crowded trees there are two summarization flags: --file-depth hides individual files below a given depth and replaces them with [+N files], and --max-items <N> shows at most N entries per directory and replaces the remainder with [+N more]. Both are documented as classic mode only, along with --du, --output and --hyperlinks. That is a meaningful constraint. The flags that exist to keep large trees readable are exactly the flags the interactive mode does not accept, so the TUI is aimed at trees you want to walk through rather than trees you want compressed. If your working directory has thousands of entries, the classic mode with --max-items is the more usable path, and the interactive mode is the one you reach for after you have narrowed down.
Installing lstr and the first commands to run
On macOS the README gives brew install lstr as the easiest route. Arch users can build the latest commit with the community-maintained lstr-git AUR package, installed via an AUR helper such as paru -S lstr-git. NetBSD has a package in the official repositories, installed with pkgin install lstr. From source on any platform, the README's steps are git clone https://github.com/bgreenwell/lstr.git, cd lstr, then cargo install --path . . The build requires the Rust toolchain, and the badge in the README states rust 1.88 or later. Once installed, lstr with no arguments lists the current directory, lstr interactive opens the TUI, and lstr -G -s --icons adds git status, sizes and glyphs in one pass. For a machine-readable listing, --output json is the flag to reach for, and --output html produces the self-contained index. Note that the README describes the HTML output as rendering directories as collapsible details elements and files as relative links, so the page is meant to be saved next to the tree it describes, not moved elsewhere.
Where lstr stops being the right tool
The clearest limitation is the mode split. Several of the most distinctive flags are classic mode only, so a workflow built around --output json cannot also use the interactive tree, and a workflow built around --expand-level cannot also use --du. The README does not describe a way to get JSON or HTML out of the interactive session. A second constraint is the Nerd Font requirement behind --icons, which makes the feature unusable on a default terminal font and awkward over SSH into a machine whose client font you do not control. A third is platform coverage in the listing itself: -p is documented as Unix-like systems only, so permission columns are not part of the Windows story even though the README's platform badge lists Windows. The README also does not document how symlink cycles are handled, what happens on a permission-denied directory mid-walk, or whether .gitignore parsing covers nested ignore files and global excludes. Those are the questions to answer before putting lstr into a script that runs unattended.
How lstr differs from tree and from exa
Against tree, the difference is the second mode and the output formats. tree prints and exits; lstr prints, or opens a TUI, or emits JSON, or writes an HTML index. The classic flags overlap closely enough that tree users will recognize -a, -L, -d and -p, and the README explicitly frames --du as behaving like tree --du. The additions are git status, icons, JSON and HTML. Against exa, a Rust ls replacement that also colors by file type and shows git status, the difference is shape rather than features. exa lists the contents of one directory, optionally in a grid or long form; lstr walks a subtree and draws connectors. If you want to know what is in this folder, an ls replacement is the shorter path. If you want to see the shape of a project, a tree walker is. lstr sits in the second category and adds a browsing mode on top of it, which is a narrower claim than it might first appear.
Licence, release cadence and what maintenance costs you
lstr is MIT licensed, which permits commercial and closed-source use provided the copyright notice and permission notice are retained, but this is a summary and not legal advice; read the LICENSE file in the repository for the actual terms. The release history in the material shows v0.2.1 in June 2025, then v0.3.0 on 2026-07-12 and v0.4.0 on 2026-07-13, so the project went roughly a year between releases and then shipped two minor versions on consecutive days. That pattern suggests bursts of work rather than a steady cadence, and it is worth checking whether the flags you depend on landed in v0.4.0 or are only on the devel branch, which is the default branch. Installing from crates.io and installing from the repository can therefore give you different feature sets. The upgrade cost itself is low: it is a single binary with no daemon and no config file mentioned in the README, so moving between versions is a matter of reinstalling and rechecking your flag combinations.
Editorial conclusion
Adopt lstr if you want a tree-style listing that can also emit JSON for scripts or a self-contained HTML index, and if a keyboard-driven TUI with filename search matches how you browse a repo. Do not adopt it if you need one consistent feature set across both modes, since --du, --output, --file-depth, --max-items and --hyperlinks are documented as classic mode only. Before installing, check the crates.io page and the devel branch for the version you will actually get, and confirm your terminal font if you plan to use --icons.
Community notes