Back to Articles

lsd: How Rust Reimagined the 40-Year-Old ls Command with Icons and Performance

[ View on GitHub ]

lsd: How Rust Reimagined the 40-Year-Old ls Command with Icons and Performance

Hook

The Unix ls command hasn’t fundamentally changed since 1979. What if you could get file type icons, tree-view formatting, and extensive color customization while maintaining the speed of a native Rust implementation?

Context

For decades, developers have stared at monochrome directory listings, mentally parsing file extensions to understand what they’re looking at. The ls command outputs text, and while GNU ls added basic color support via LS_COLORS, it remains fundamentally spartan. Ruby’s colorls demonstrated that rich, icon-enhanced listings were possible, but interpreted languages brought performance concerns.

Enter lsd (LSDeluxe), a complete reimplementation of ls in Rust that combines aesthetics with the performance characteristics of a compiled systems language. With over 15,000 GitHub stars, lsd has become a popular ls replacement for developers who spend hours daily in terminals. It renders file type icons via Nerd Fonts, applies sophisticated color schemes, and maintains tree-view formatting—all implemented in Rust, which provides memory safety without garbage collection overhead.

Technical Insight

Rendering Pipeline

YAML files

config.yaml

colors.yaml

icons.yaml

file metadata

permissions, size, date

file type/extension

Nerd Font glyphs

layout mode

CLI Arguments Parser

Config Loader

Config Merger

General Settings

Color Theme

Icon Mappings

Filesystem Traversal

Metadata Extractor

Block Builder

Formatted Blocks

Icon Resolver

Output Colorizer

Terminal Output

System architecture — auto-generated

At its core, lsd is a Rust-based reimplementation of GNU ls with extensive customization capabilities. The tool reads configuration from YAML files, allowing deep customization of colors, icons, and behavior without recompilation. Configuration can be split across three files: config.yaml for general settings, colors.yaml for color theming, and icons.yaml for icon mappings.

The icon system uses Nerd Fonts, where file extensions and types map to Unicode glyphs. Here’s how you’d configure display settings in your config.yaml:

icons:
  when: auto  # auto, always, never
  theme: fancy
  separator: " "

color:
  when: auto
  theme: default

layout: grid  # grid, tree, oneline

blocks:
  - permission
  - user
  - group
  - size
  - date
  - name

date: relative  # date, relative, +date-format

The blocks configuration demonstrates lsd’s composable output model—each metadata type (permissions, size, dates) is an independent block that can be reordered or removed. The date: relative option allows displaying dates as relative time (e.g., “2 days ago”) instead of absolute timestamps, making temporal context immediately scannable.

The tree-view mode can be invoked with lsd --tree, producing hierarchical output with full icon and color support:

lsd --tree --depth 2

This renders a hierarchical view where directories get folder icons, executables get gear icons, and symlinks show arrow indicators. The color theming system allows extensive customization through the colors.yaml file, and icons can be customized per file type through icons.yaml. Sample configuration files are provided in the project’s documentation folder to help users get started with customization.

Gotcha

The Nerd Font dependency is lsd’s biggest setup hurdle. Out of the box on a fresh system, you’ll see tofu characters (empty boxes) instead of icons until you install and configure a patched font. This isn’t a five-minute setup—you need to download a Nerd Font, install it system-wide, configure your terminal emulator to use it, and potentially adjust font rendering settings. For teams onboarding new developers, this adds friction to dotfile setups.

Script compatibility is another genuine concern. While lsd supports many ls flags, subtle output formatting differences exist. If you have shell scripts that parse ls output (already a code smell, but common in legacy codebases), replacing ls with lsd via an alias can break things. The default grid layout differs from ls’s column behavior, and formatting variations might confuse naive parsing logic. Production automation should use find, stat, or structured tools rather than parsing ls output. The README documentation is explicit about installation requirements but users should be aware that the visual features come with setup overhead.

Verdict

Use lsd if you’re building a developer-focused terminal environment where visual clarity improves productivity, you’ve already invested in Nerd Fonts (or are willing to), and you primarily interact with directories through manual exploration rather than scripting. It’s perfect for daily workflows where distinguishing file types at a glance matters—frontend developers juggling multiple file extensions, DevOps engineers scanning through config files, or any developer navigating large directory structures. Skip lsd if you need guaranteed GNU ls compatibility for legacy scripts, work in constrained environments like minimal Docker images where fonts are impractical, require output parsability for automation (use find -printf or structured alternatives instead), or simply prefer minimalism and don’t value the visual enhancements. For SSH jump boxes and production servers, stick with standard ls to avoid dependency complexity—lsd shines in local development environments where you control the tooling and font configuration.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/cybersecurity/lsd-rs-lsd.svg)](https://starlog.is/api/badge-click/cybersecurity/lsd-rs-lsd)