Skip to content
Shell & TerminalNews Published Updated 3 min readViews unavailable

Fish Ships as a Shell That Deliberately Breaks From POSIX

Released February 13, 2005 by Swedish developer Axel Liljencrantz, Fish chose sensible-by-default behavior and built-in syntax highlighting over POSIX compatibility.

On February 13, 2005, Swedish developer Axel Liljencrantz released the first version of fish (the friendly interactive shell) — a shell that made a genuinely different bet than Bash or Zsh, deliberately sacrificing POSIX compatibility for more consistent syntax and better defaults out of the box.

Why fish chose to break compatibility deliberately

Where Bash and Zsh both maintain substantial POSIX shell compatibility as a design constraint, fish’s design explicitly prioritized eliminating confusing, historically-inherited POSIX shell syntax quirks — accepting that existing POSIX shell scripts wouldn’t run unmodified under fish, in exchange for scripting syntax its designers considered more consistent and easier to learn from scratch.

What fish provided by default that other shells needed configuration or plugins for

From early on, fish included syntax highlighting (commands and arguments colored differently, invalid commands flagged visually) and autosuggestions (based on history and completions, shown as you type) as built-in, zero-configuration behavior — features that, on Bash or Zsh, generally require third-party plugins or frameworks to achieve anything comparable.

Liljencrantz’s role and what followed

Liljencrantz served as fish’s primary maintainer through its early versions, up to version 1.23.1, with development later continuing on GitHub through community contribution — the project reached version 2.0 in September 2013 and version 3.0 in December 2018, continuing active development for two decades after its original release.

Why fish remains a minority but persistent choice

Despite never approaching Bash’s or Zsh’s overall adoption, fish has maintained a consistent, dedicated user base specifically among users who value its out-of-the-box usability enough to accept POSIX incompatibility as a worthwhile tradeoff — a genuinely different answer to the same underlying question Zsh and its ecosystem of frameworks also try to answer: how to make daily interactive shell use less painful.

Two decades on, fish rebuilt its own foundation entirely

Two decades after that first 2005 release, the fish maintainers undertook a genuinely large engineering effort: a roughly 14-month project, beginning as a half-joking pull request titled “Rewrite it in Rust,” that ultimately translated over 57,000 lines of C++ into around 75,000 lines of Rust across more than 2,600 commits from over 200 contributors, shipping as fish 4.0. The team deliberately ported component by component rather than rewriting from scratch all at once, keeping the shell in a working state at every intermediate step — a considerably more conservative migration strategy than a clean-slate rewrite, and one that let fish keep shipping normal releases throughout the transition rather than freezing development for over a year.

Why the maintainers considered a rewrite worth the risk at all

The team’s own stated motivation centered on Rust’s compile-time guarantees around thread safety — specifically the Send and Sync traits, which let the compiler statically enforce rules about which data can safely cross thread boundaries, rather than relying on manual discipline and runtime testing to catch concurrency bugs the way the original C++ codebase had to. For a shell whose core value proposition was already “sensible defaults, fewer footguns,” extending that same philosophy to the implementation language itself, not just the user-facing scripting syntax, is a coherent continuation of fish’s original 2005 design priorities two decades later, applied to the shell’s own implementation, not just to what a user directly types at the interactive prompt each day.

Related:

Sources:

Comments