zlist

July 24, 2026 · View on GitHub

A modern, colorful alternative to ls built with Zig.

Build Status Zig Version License

Note: This is my first CLI tool in Zig! 🚀

I built this project to learn Zig, get comfortable with manual memory management, and explore the standard library. It might not be the fastest or smallest ls clone (yet), but it's usable today and still getting better.

Table of Contents

Features

Already pretty capable for a learning project:

  • Compact grid layout that stays easy to scan.
  • Color and Nerd Font icons for common file types and languages.
  • Readable long view with permissions, owner, size, and timestamps.
  • Optional recursive directory size in long view and size sorting.
  • Multiple sort modes including name, length, directories first, mtime, and size.
  • Recursive listing with optional depth limits.
  • Useful filters for files, directories, extensions, names, size, and modified time.
  • Quick summary report for file and folder counts.
  • Git status indicators in long view.

Preview

Preview1 Preview2 Preview3

(Make sure you have a Nerd Font installed in your terminal to see the icons!)

Installation

macOS

Install with Homebrew:

brew tap here-leslie-lau/tap
# Maybe need trust
brew install zlist

Precompiled Binaries

Download the latest binary for your system from the Releases page.

Note: Windows is currently not supported due to differences in file system APIs. Support may be added in future versions.

From Source

Requirements: zig (master/0.17.0-dev recommended).

# 1. Clone the repo
git clone git@github.com:here-Leslie-Lau/zlist.git
cd zlist

# 2. Build in release mode [ReleaseFast, ReleaseSafe, ReleaseSmall]
zig build -Doptimize=ReleaseFast

# 3. Run it. (Optional: add to PATH, it's up to you.)
./zig-out/bin/zl

Usage

Just run:

zl [OPTIONS] [PATH]
$ zl --help
    -h, --help
            Usage: zl [OPTIONS] [PATH]...

    -l, --long
            Show the long view.

    -H, --header
            Show header in the long view.

        --no-permissions
            Hide permissions from the long view.

        --no-user
            Hide user from the long view.

        --no-group
            Hide group from the long view.

        --no-size
            Hide size from the long view.

        --no-time
            Hide time from the long view.

        --no-icon
            Hide icon from the long view.

    -a, --a
            Include hidden entries.

        --du
            Show recursive directory size in long view and size sort. This is the sum of file sizes, not the same as `du` disk usage.

        --dir-grouping <DIRGROUPING>
            Group directories before or after files. Default: none. OPTIONS: none, before, after.

    -s, --sort <SORTTYPE>
            Sort results. Default: name. OPTIONS: name, length, mtime, size.

        --reverse
            Reverse sort.

        --size <str>...
            Filter files by size range (e.g. --size gt:10K --size lte:2M).

        --changed-within <str>
            Only show entries changed within a time range (e.g. --changed-within 7d).

    -r, --recursive
            Recurse into subdirectories. Same as -L 0.

    -L, --level <INT>
            Limit recursion depth. 0 means no limit.

        --root-display <ROOTDISPLAY>
            Changes how root dir is displayed in recursive view. Default: dot. OPTIONS: dot, name, none.

    -p, --pure
            Show names only, without colors or icons.

    -R, --report
            Show a short summary of files and folders.

    -d, --dir
            Only show directories. If used with -D, both are ignored.

    -D, --no_dir
            Only show files. If used with -d, both are ignored.

    -g, --git
            Show git status in long view.

    -e, --ext <str>...
            Filter by extension (e.g. --ext zig,md,ts).

    -m, --match <str>...
            Filter names by substring (e.g. --match main,readme).

    <str>...

For common commands examples, see zlist examples.

Use as a Zig Module

zlist can also be used from another Zig project when you want the listing data without the CLI output.

Add it with Zig's package manager:

zig fetch --save git+https://github.com/here-Leslie-Lau/zlist

Then expose the module in your build.zig:

const zlist_dep = b.dependency("zlist", .{
    .target = target,
    .optimize = optimize,
});

exe.root_module.addImport("zlist", zlist_dep.module("zlist"));

Use it from code:

const std = @import("std");
const zlist = @import("zlist");

fn printNames(allocator: std.mem.Allocator, io: std.Io, dir: std.Io.Dir) !void {
    var files = try zlist.Files.init(allocator, io, dir, .{ .path = "." });
    defer files.deinit();

    for (files.entries()) |entry| {
        std.debug.print("{s}\n", .{entry.name});
    }
}

For options, ownership rules, and more examples, see Using zlist as a module.

Benchmark

Benchmarked with hyperfine on macOS with an Apple M4 CPU.

With icons and colors:

Tooln=50n=500n=5000n=50000
zl696.4 µs ± 59.4 µs957.2 µs ± 62.2 µs4.4 ms ± 0.1 ms45.9 ms ± 2.1 ms
eza3.0 ms ± 0.2 ms2.8 ms ± 0.2 ms2.9 ms ± 0.1 ms3.1 ms ± 0.2 ms
lsd2.9 ms ± 0.1 ms10.7 ms ± 0.6 ms97.8 ms ± 2.1 ms1.227 s ± 0.055 s

eza is the weirdly steady one here: its wall time barely moves whether the directory has 50 files or 50K. Its system CPU time also stays under 2 ms even at 50K entries. zl is already quick at smaller sizes, but this is exactly the kind of scaling behavior it should learn from next.

Benchmark results may vary depending on filesystem and hardware.

Roadmap

  • Basic file listing & recursion
  • Color output & Nerd Font icons
  • Detailed file stats
  • Sorting by name (default), length, and modification time
  • Recursive directory traversal (-r)
  • Depth control for recursion (-L)
  • Clean output mode (-p)
  • Filter by files or directories (-d, -D)
  • Extension filter (-e, --ext)
  • Name match filter (-m, --match)
  • Smart dynamic grid layout
  • Summary report (-R)
  • Git status integration (-g)
  • Recursive directory size (--du)
  • Lib API for embedding in other Zig projects
  • Multi-threading for faster stat calls
  • Custom color/icon configurations (Maybe, if you need it)

Contributing

Got an idea? Found a bug? Open an issue or send a PR. This is a fun side project, and contributions are always welcome.

  1. Fork it
  2. Create your feature branch (git checkout -b feature/cool-thing)
  3. Commit your changes
  4. Push to the branch
  5. Open a Pull Request

Crafted with ❤️ in Zig.