TechEarl

exa and eza: A Modern ls Replacement

exa was the modern ls replacement with color, a git column, and a tree view in one binary; it is now unmaintained and eza is the drop-in fork to install instead. The flags, the eza migration, and when plain ls is still the right call.

Ishan Karunaratne⏱️ 9 min readUpdated
Share thisCopied
exa and eza are modern ls replacements for the terminal: colorized output, a built-in git status column, tree view with -T, icons, and a long-listing that beats ls -l. eza is the maintained fork to install now that exa is unmaintained.

exa was a modern ls replacement: one Rust binary that gave you colorized output, a git status column, a tree view, and human-readable sizes without a single alias. The thing to know in 2026 is that exa is no longer maintained, and the drop-in replacement is eza, a community fork that picks up where it stopped. So the practical answer is: install eza, not exa.

bash
# Debian 13+ / Ubuntu 24.04+ (older releases: use the deb.gierens.de repo)
sudo apt install eza

# Fedora 41 and older
sudo dnf install eza
# Fedora 42+ (dropped from the official repos; use the COPR or a release binary)
sudo dnf copr enable alternateved/eza && sudo dnf install eza

# Arch
sudo pacman -S eza

# macOS
brew install eza

eza keeps the same command surface as exa, so everything below works against either binary; just substitute the name. If you already have an exa install, your muscle memory and your aliases port over unchanged. The rest of this page is the flag reference, the migration, and the honest list of when plain ls is still the better tool.

Why exa, and why eza now

exa shipped sensible defaults that ls never had: a colored, column-aligned grid that distinguishes file types at a glance, sizes in K/M/G without needing -h, and a git-aware long view. It was popular enough to land in most distro repos.

Then development stalled. exa's last release was v0.10.1 in April 2021, and the project's own README now reads "exa is unmaintained, use the fork eza instead." (The repo is not formally archived only because the one person with rights to archive it is unreachable.) Open issues and pull requests sit unmerged, and some distributions have since dropped the package. eza is the maintained fork that took over: same author-facing behavior, same flags, ongoing bug fixes and new features (hyperlink support, better theming via a config file, more --git accuracy). If you are choosing today, choose eza. If you inherited an exa install, it still runs, but it will not get fixes.

I will write eza from here on. Replace it with exa mentally if you are on an older box that still has it.

The long view: eza -l

The command you will use most:

bash
eza -l

That prints the long listing: permissions, size, modified date, and name, one file per line, colorized by type. It is the ls -l equivalent, but the size column is human-readable by default and the colors actually mean something.

Stack the common flags the way you would with ls:

bash
eza -la          # long view, including dotfiles
eza -la --git    # ...plus a git status column
eza -lah         # the -h here shows file headers, not "human sizes"

One gotcha for ls muscle memory: in eza, -h is not "human-readable sizes" (those are already on); -h means --header, which prints a column header row. Sizes are human by default, so you rarely need to think about it.

The git status column: --git

bash
eza -l --git

This adds a two-character column showing each file's git status relative to the index and working tree: N for new/untracked, M for modified, staged versus unstaged shown in the two positions. It only does anything inside a git repository; outside one, the column is blank. It is the feature that made exa worth installing, and eza keeps it.

A worked example inside a repo with one tracked edit and one new file:

code
$ eza -l --git
-M .rw-r--r--  1.2k techearl  5 Apr 10:14 readme.md
-N .rw-r--r--   840 techearl  5 Apr 10:15 notes.txt
-- .rw-r--r--  3.1k techearl  2 Apr 09:02 config.toml

The git column is the leftmost one, two characters wide: the first position is the staged state, the second is the unstaged state. readme.md is modified in the working tree (-M), notes.txt is new and untracked (-N), config.toml is clean (--). No git status needed for a quick glance.

The tree view: eza -T

bash
eza -T

-T (or --tree) prints the directory as a tree, the same shape the standalone tree command gives you, but with eza's colors, git awareness, and the ability to bolt on a long view. Limit the depth so you do not dump an entire node_modules:

bash
eza -T --level=2          # two levels deep
eza -lT --level=2 --git   # tree + long columns + git status
eza -T --git-ignore       # tree, but skip files in .gitignore

--git-ignore is the one I reach for most in a project root: it respects .gitignore, so the tree shows the files you actually care about instead of build output.

Icons and grouping

bash
eza --icons

--icons prefixes each entry with a Nerd Font glyph for its file type. It only renders correctly if your terminal font is a patched Nerd Font; without one you get tofu boxes. Worth setting up once, then it is on for good via an alias.

A couple more flags that earn their keep:

bash
eza -l --group-directories-first    # directories sorted to the top
eza -l --sort=modified               # oldest first; add --reverse for newest first
eza -l --no-permissions --no-user    # trim columns you do not need

eza vs ls: the flag map

If you know ls, this is the translation table. Most ls short flags carry over, with a few that mean something different.

Tasklseza
Long listingls -leza -l
Include dotfilesls -laeza -la
Human-readable sizesls -lheza -l (default)
Sort by modified timels -lteza -l --sort=modified
Reverse sortls -lreza -l --reverse
Recursivels -Reza -R
Tree view(tree)eza -T
Git status column(none)eza -l --git
Column header row(none)eza -lh / eza -l --header

The standout difference is -h. On ls, -h is human-readable sizes; on eza, sizes are human by default and -h is --header. The other trap is that eza does not implement every obscure ls flag, so a script that leans on ls -1 --quoting-style=... will not port verbatim. For interactive use the map above covers almost everything.

Make it your default with an alias

Once you trust it, alias ls to eza in your shell rc so the new behavior is the default:

bash
# ~/.bashrc or ~/.zshrc
alias ls='eza --group-directories-first'
alias ll='eza -la --git --group-directories-first'
alias lt='eza -T --level=2 --git-ignore'

Keep the real ls reachable: command ls or \ls bypasses the alias when a script or a habit needs the original. That matters because aliasing ls to a tool that may not be installed everywhere is exactly how a copy-pasted shell snippet breaks on a server that has never heard of eza.

When plain ls is still the right call

eza is a better interactive ls. It is not a universal replacement, and a few situations call for the original:

  • Scripts and portability. ls is in POSIX and present on every Unix box, including minimal Alpine containers and stripped-down servers. eza is an extra install. Never alias ls to eza in a way that leaks into scripts; parse with find, stat, or globbing rather than scraping eza output anyway.
  • Machine-readable output. If you are piping into awk or cut, the colorized, human-sized eza output is harder to parse than ls -l --time-style=... or, better, stat and find -printf. Do not parse ls either, but if you must, ls is the more stable contract.
  • A box where you cannot install anything. On a locked-down production host, ls is what you have. Learn ls -lhtr and move on.
  • Disk usage, not listings. eza lists files; for "what is eating my disk" reach for a real disk tool. The duf disk usage df replacement covers the friendlier df/du alternatives.

For day-to-day work in a terminal you control, eza wins on legibility. For anything that has to run somewhere else, write it against ls or the proper tool.

See also

FAQ

Sources

Authoritative references this article was fact-checked against.

TagsexaezalsCLILinuxmacOSShell Scripting

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

grep Regex: BRE vs ERE vs PCRE Explained

grep has three regex engines and the default one surprises everyone: in basic regex (BRE) the characters + ? | ( ) { } are literal text until you backslash-escape them. -E switches to extended regex (ERE) where they work bare, and -P unlocks Perl-compatible regex with lookaround and \d. The full BRE vs ERE vs PCRE comparison, the same pattern in all three, and why -P does not exist on macOS.