There is a particular kind of pause that happens after cloning someone else’s repository. You know the answer is somewhere inside it, but the directory names do not yet tell a story. tree is useful in that moment. It does not search file contents or explain the architecture; it gives your eyes a map, and a good map makes the next question easier.

The examples below were executed with tree 2.1.1 on Ubuntu 24.04 against a disposable TypeScript-shaped fixture containing src, tests, docs, node_modules, hidden entries, and a symbolic link. Substitute your own project path when following along.

First, make sure this is the tree you think it is

Terminalbash
command -v tree
tree --version
/usr/bin/tree
tree v2.1.1

Two lines, two different assurances

  • command -v reveals the executable selected by the current shell, which helps catch aliases, wrappers, or a missing command.

  • tree --version identifies the feature set under test; options such as --gitignore are not available in every older release.

  • The locally tested Ubuntu package identifies itself as 2.1.1; your distribution may package another maintained version.

Install it only if the command is missing

Terminalbash
sudo apt update
sudo apt install tree

Risk level: caution. Review the command before running it.

What APT changes here

  • apt update refreshes repository metadata; apt install then resolves and installs the package selected for your Ubuntu release.

  • Review the source and transaction summary before confirming a package change.

  • On Fedora-family systems the package is also named tree and is commonly installed with DNF; on Arch Linux it is available through pacman. Use the native package manager rather than an untrusted binary download.

The first map should be small enough to read

Terminalbash
tree -L 2 lynxbee-tree-demo
lynxbee-tree-demo
├── README.md
├── docs
│   ├── archive
│   └── guide.md
├── node_modules
│   └── pkg
├── source-link -> src
├── src
│   ├── app.ts
│   └── lib
└── tests
    └── app.test.ts

9 directories, 4 files

Read the shape before reading every name

  • -L 2 limits descent to two levels below the named root; it does not mean “show two items.”

  • Without a directory argument, tree begins at the current working directory.

  • The final report counts entries visited within the chosen view. Filters and depth limits therefore change the totals.

  • The arrow shows source-link is a symbolic link to src; default output names the target without descending through it.

Hidden files change the story—and the risk

Terminalbash
tree -a -L 1 lynxbee-tree-demo
lynxbee-tree-demo
├── .env
├── .github
├── README.md
├── docs
├── node_modules
├── source-link -> src
├── src
└── tests

7 directories, 2 files

Why -a deserves respect

  • -a includes names beginning with a dot, though . and .. themselves are never printed.

  • Hidden names can reveal repository configuration, credentials files, private keys, editor state, and deployment details.

  • This example exposes the name .env, not its contents. Even filenames can be sensitive in screenshots, tickets, or public documentation.

  • Sanitize output before sharing it; never assume a directory listing is harmless because it contains no file contents.

Remove the branches that drown out the answer

Terminalbash
tree -I 'node_modules|archive' lynxbee-tree-demo
lynxbee-tree-demo
├── README.md
├── docs
│   └── guide.md
├── source-link -> src
├── src
│   ├── app.ts
│   └── lib
│       └── config.ts
└── tests
    └── app.test.ts

6 directories, 5 files

The quotes are doing real work

  • -I excludes matching files or directories from the listing.

  • Inside tree’s pattern language, | separates alternatives, so this expression excludes either node_modules or archive.

  • Single quotes prevent the shell from interpreting wildcard characters or the pipe before tree receives them.

  • Filtering output is not deletion. The excluded directories remain untouched on disk.

Ask for one kind of file and prune the empty scaffolding

Terminalbash
tree -P '*.ts' --prune lynxbee-tree-demo
lynxbee-tree-demo
├── src
│   ├── app.ts
│   └── lib
│       └── config.ts
└── tests
    └── app.test.ts

4 directories, 3 files

Matching is not searching file content

  • -P includes filenames matching tree’s wildcard pattern; it does not inspect the text inside those files.

  • *.ts is quoted so the shell cannot expand it against only the current directory.

  • --prune removes empty directories from the filtered presentation, which is why docs and node_modules disappear.

  • Use rg when the question is “which file contains this text?” and find when you need richer predicates or actions. Use tree when relationships are the point.

Sometimes you want only the rooms, not what is inside them

Terminalbash
tree -d -L 2 lynxbee-tree-demo
lynxbee-tree-demo
├── docs
│   └── archive
├── node_modules
│   └── pkg
├── source-link -> src
├── src
│   └── lib
└── tests

9 directories

A directory-only view is an architecture sketch

  • -d suppresses regular files, leaving a quick picture of module, package, documentation, and test boundaries.

  • The symbolic link is counted as a directory entry in this view but is still shown as a link.

  • Combine -d with -L, -I, or --dirsfirst when preparing a concise project overview.

Add metadata when names alone cannot answer the question

Terminalbash
tree -p -h -L 1 lynxbee-tree-demo
[drwxr-xr-x 4.0K]  lynxbee-tree-demo
├── [-rw-rw-r--    0]  README.md
├── [drwxrwxr-x 4.0K]  docs
├── [drwxrwxr-x 4.0K]  node_modules
├── [lrwxrwxrwx    3]  source-link -> src
├── [drwxrwxr-x 4.0K]  src
└── [drwxrwxr-x 4.0K]  tests

Do not mistake an entry size for directory usage

  • -p prints file type and permission bits in the familiar ls -l style.

  • -h makes each entry’s own size readable; a directory’s entry size is not the total space consumed by everything beneath it.

  • Use --du when you need cumulative directory sizes, but expect tree to read the entire selected subtree before emitting output.

  • For interactive disk-usage investigation, ncdu provides a purpose-built view.

Terminalbash
tree -l -L 2 lynxbee-tree-demo/source-link
lynxbee-tree-demo/source-link
├── app.ts
└── lib
    └── config.ts

2 directories, 2 files
  • -l follows symbolic links that point to directories; without it, tree prints the target path but does not descend.

  • Tree detects recursive link loops, but following links can still traverse much more data than expected.

  • Add -x when a diagnostic must remain on the current filesystem, especially near mounts or network filesystems.

  • Check the root path before combining -l with an unrestricted depth or cumulative size calculation.

When another program needs the map

Terminalbash
tree -J -L 1 lynxbee-tree-demo
[
  {"type":"directory","name":"lynxbee-tree-demo","contents":[
    {"type":"file","name":"README.md"},
    {"type":"directory","name":"docs"},
    {"type":"directory","name":"node_modules"},
    {"type":"link","name":"source-link","target":"src"},
    {"type":"directory","name":"src"},
    {"type":"directory","name":"tests"}
  ]},
  {"type":"report","directories":6,"files":1}
]

JSON changes the consumer, not the traversal

  • -J emits a JSON array containing the tree plus a final report object.

  • -L 1 still controls traversal depth; output format does not make an unbounded walk cheap.

  • Validate and parse the JSON instead of scraping Unicode branch characters in automation.

  • Treat filenames as untrusted data when generating HTML, dashboards, or shell commands from the output.

A few combinations worth remembering

  • tree --dirsfirst -L 2: place directories before files for an onboarding-friendly overview.

  • tree --gitignore: honor supported .gitignore rules when the installed version provides this option.

  • tree -Q: quote filenames, which helps expose spaces and unusual names unambiguously.

  • tree -D --timefmt "%Y-%m-%d %H:%M": add formatted modification times.

  • tree --filelimit 200: avoid descending into directories with more than 200 entries.

  • tree -n: suppress color escape sequences when capturing output in logs or documentation.

Where tree stops being the right tool

  • Find files by size, type, owner, or age: use the Linux find command.

  • Measure disk consumption interactively: use ncdu.

  • List files installed by a package: query the package database with the installed-files workflow.

  • Search source text: use rg or another content searcher; tree only knows directory metadata.

  • Feed stable automation: prefer JSON or NUL-safe purpose-built tools over parsing decorative terminal output.

The small habit that makes tree useful

Do not begin by printing everything. Begin with the directory you care about, two levels deep, and one question in mind. Add hidden files, metadata, matching, or link traversal only when that question asks for them. The result stays readable—and an unfamiliar repository starts feeling less like someone else’s maze.

Validated reference

Option behavior and output were checked locally against tree 2.1.1 on Ubuntu 24.04 and against the installed tree(1) manual. Consult man tree on your machine for the authoritative behavior of its exact build.