Fish vs Zsh
Fish and Zsh compared for developers: out-of-the-box features, autosuggestions and completions, POSIX and Bash compatibility, scripting, configuration, plugin ecosystems like Oh My Zsh, licensing and release status as of November 2026.
Quick Answer
Zsh is the default login shell on every new macOS account since 10.15, highly compatible with sh and mostly compatible with Bash. It is endlessly configurable through its completion system, ZLE line editor and frameworks such as Oh My Zsh, whose README promises hundreds of plugins and themes. Its latest release is 5.9.2 (12 Jul 2026, a bug-fix release), and a larger 5.10 is in development. Fish (4.9.3, 8 Sep 2026, core ported from C++ to Rust in 4.0) gives you autosuggestions, syntax highlighting, rich completions, abbreviations and a web-based config tool with zero setup. In exchange it is intentionally not POSIX-compatible: no heredocs, no subshells, no $(( )) arithmetic and no Bash-style word splitting. Pick fish if you want the best interactive shell with no dotfile work and you are happy writing scripts in Bash or sh anyway. Pick zsh if you paste Bash snippets all day, share dotfiles with a team, or want deep control over every key and completion.
Last updated November 3, 2026. Covers fish 4.9.3 (8 Sep 2026) and zsh 5.9.2 (12 Jul 2026) plus the in-development 5.10 changes, using fish docs and release notes, zsh source files (README, NEWS, FAQ, LICENCE), Apple's zsh support page and GitHub data.
| Feature | Fish | Zsh |
|---|---|---|
| Licence | GPL-2.0 (most code; some parts PSF-2.0, MIT, LGPL-2.0) | Zsh licence (MIT-style permissive); some shell functions GPL |
| Written In | Rust (ported from C++ in 4.0.0, Feb 2025) | C |
| POSIX / Bash Compatibility | Intentionally not POSIX; no heredocs, subshells or $(( )); $(cmd) and (cmd) supported | Highly sh-compatible, mostly Bash-compatible; emulate sh/ksh modes |
| Autosuggestions | Built in (history, completions, valid paths) | Via plugin (zsh-autosuggestions) |
| Syntax Highlighting | Built in, configurable via fish_color_* variables and themes | Via plugin (zsh-syntax-highlighting); region_highlight in ZLE |
| Completions | Built in, many program-specific completions loaded on demand | compinit completion system, context-sensitive and programmable |
| Configuration | ~/.config/fish/config.fish, conf.d, functions/; fish_config web UI; universal variables | .zshenv, .zprofile, .zshrc, .zlogin; zsh/newuser module for first-run setup; frameworks like Oh My Zsh |
| Abbreviations / Aliases | abbr with in-place expansion, regex and function abbreviations; aliases via functions | alias and global aliases (alias -g); abbreviations via plugins |
| Scripting Language | fish language: set -l/-g/-U/-x scoping, no word splitting, math and string builtins | Bourne-style with ksh/zsh extensions (arrays, associative arrays, glob qualifiers) |
| Plugin Ecosystem | Smaller: third-party plugin managers and themes; most features need no plugins | Very large: Oh My Zsh, zsh-users plugins, many plugin managers and prompt themes |
| Default Shell On | No major OS by default | macOS 10.15 Catalina and later (new accounts) |
| Install Options | macOS installer/app, Homebrew, MacPorts, Linux packages and standalone binaries, BSDs, Cygwin, MSYS2, WSL | Preinstalled on macOS; packages on virtually every Linux distro and BSD |
| Latest Release (Nov 2026) | 4.9.3 (8 Sep 2026) | 5.9.2 (12 Jul 2026, bug-fix); 5.10 in development |
Fish
The friendly interactive shell: a GPL-2.0 command-line shell for Linux, macOS and the BSDs, written in Rust since 4.0, that ships autosuggestions, syntax highlighting, completions and a clean scripting language with no configuration required.
Pros
- Works out of the box: autosuggestions from history, completions and valid paths, live syntax highlighting and 24-bit colour with an empty config
- Large set of program-specific completions loaded on demand, for example make targets from the Makefile and installed or installable packages for apt, rpm and yum
- Abbreviations expand in place as you type, so gco becomes git checkout in your history; they can use regexes and functions, and 4.9 added descriptions shown in the completion pager
- Consistent scripting syntax: no word splitting so quoting mistakes bite less, a math builtin with floating point, and a string builtin for splitting and manipulation
- fish_config opens a browser-based tool for colours, prompts, functions, variables and history, and universal variables persist settings across all sessions instantly
- Easy installs everywhere: macOS installer and app (10.12+), standalone Linux binaries for x86_64 and aarch64, packages for major distros and the BSDs, Cygwin and MSYS2
Cons
- Intentionally not POSIX-compatible: Bash snippets with heredocs, subshells, $(( )) arithmetic, backticks or <(...) process substitution need rewriting
- No !! or !$ history substitution by default (the FAQ shows how to emulate !! with an abbreviation)
- config.fish is read by every shell, including non-interactive ones started by ssh, scp and rsync, so any output there must be guarded with status is-interactive
- Scripts written in fish only run where fish is installed, so most teams still write shared scripts in Bash or sh
- Smaller plugin ecosystem than zsh and Oh My Zsh
Best For
Developers who want a fast, helpful interactive shell with no dotfile tinkering, and who keep their portable scripts in Bash or sh.
Zsh
The Z shell: a Bourne-style shell designed for interactive use and powerful scripting, highly compatible with sh and mostly compatible with Bash, with a programmable completion system and line editor. It is the default shell on macOS.
Pros
- Default login and interactive shell for new user accounts on macOS since 10.15 Catalina, so it is already there on every recent Mac
- Highly compatible with sh and mostly compatible with Bash, per Apple's documentation, so most Bash one-liners and snippets paste straight in
- emulate sh and emulate ksh switch on compatibility options when you need stricter behaviour, for example inside a function
- Context-sensitive completion system (compinit) and a fully programmable line editor (ZLE) with emacs and vi keymaps
- Huge ecosystem: Oh My Zsh (MIT, about 190k GitHub stars, hundreds of plugins and themes), plus zsh-autosuggestions and zsh-syntax-highlighting, which bring fish-style features to zsh
- Permissive MIT-style Zsh licence for the shell itself, with only some optional shell functions under the GPL
Cons
- Bare zsh does little: autosuggestions and syntax highlighting need plugins, and completions need compinit in your .zshrc
- Heavy frameworks and many plugins can slow shell startup, and debugging someone else's .zshrc is a common time sink
- Differs from Bash in subtle ways (for example no word splitting of unquoted parameters unless SH_WORD_SPLIT is set), which can surprise script authors
- Release cadence is slow: 5.9 shipped in May 2022 and only bug-fix releases 5.9.1 and 5.9.2 followed in 2026, while 5.10's new features are still unreleased
- The completion system is powerful but complicated; its own FAQ calls the zshcompsys manual complicated
Best For
Developers who live in Bash-flavoured documentation, share dotfiles across a team or fleet, or want fine-grained control over completion, keybindings and prompts, especially on macOS where it is the default.
Out-of-the-box experience vs build-your-own
The biggest difference shows on day one. Fish's homepage promises tab completions and syntax highlighting that just work, and its interactive docs describe autosuggestions drawn from your history, completions and valid file paths, shown in muted grey after the cursor and accepted with the right arrow or ctrl-f. Highlighting colours commands, arguments and errors as you type, and the completion pager can be searched with ctrl-s. None of this needs a config file. Zsh gives you the engine and expects you to assemble the car. Apple's support page notes zsh's comprehensive command-line completion system, but you enable it by running compinit from your .zshrc. Autosuggestions come from the zsh-autosuggestions plugin, whose README describes it as fish-like, and highlighting comes from zsh-syntax-highlighting, which bills itself as fish shell-like syntax highlighting for zsh. Most people install Oh My Zsh, an MIT-licensed framework with about 190k GitHub stars that its README says offers hundreds of plugins and themes. The end result can match fish and go well beyond it, with custom widgets, prompts and keymaps. But you own that configuration, and heavy setups are a common cause of slow shell startup. If your goal is simply a pleasant shell, fish gets there in one install. If you enjoy tuning, zsh rewards it more.
Compatibility: POSIX, Bash and pasted snippets
This is the trade-off that decides it for many developers. Fish's own fish for Bash users guide states that fish is intentionally not POSIX-compatible. Concretely, it has no heredocs, so you use printf or multi-line quotes instead, and no subshells. Arithmetic expansion like $((i+1)) is replaced by the math builtin, which handles floating point. Process substitution <(cmd) becomes (cmd | psub), with no equivalent for >(cmd), and backticks are not supported, though $(cmd) and (cmd) both work. Variables use set with scope flags rather than export or local, and fish does not perform word splitting, so command substitutions split only on newlines. Since fish 3.1, VAR=value cmd works for one-off environment overrides, and 4.9 now errors on mistakes like status=123. Zsh sits much closer to Bash. Apple describes it as highly compatible with the Bourne shell and mostly compatible with Bash, and the zsh FAQ notes that emulate sh or emulate ksh switches on the relevant options. The classic gotcha the FAQ calls out is word splitting: unquoted parameter expansions are not split unless SH_WORD_SPLIT is set. For daily use, almost everything you copy from a README or Stack Overflow answer will run in zsh. In fish, you will rewrite a few constructs or run them with bash -c.
Scripting and configuration files
Fish's language is smaller and more regular. Blocks end with end, conditions use if, and, or and not, and variables have explicit scopes: local, global, universal or exported. Universal variables, set with set -U, are shared instantly across all running sessions and persist across restarts. That is handy for themes and settings, though the FAQ warns that an inherited global variable takes precedence over a universal one of the same name. Configuration lives in ~/.config/fish/config.fish plus conf.d snippets and an autoloaded functions directory. One sharp edge: config.fish is read by every fish process, interactive or not. The FAQ explains that output from it breaks ssh, scp and rsync when fish is your login shell, so wrap anything noisy in if status is-interactive. Fish 4.8 added cd -L and -P, and 4.9 relaxed nested list indexing. Zsh scripts are Bourne-style with extensions such as arrays, associative arrays and glob qualifiers, and zsh splits configuration across .zshenv, .zprofile, .zshrc and .zlogin by shell type. The in-development 5.10 adds named references and namespaces, non-forking ${ ... } command substitution, GNU-style option parsing in zparseopts and monotonic internal timing. Whichever shell you use interactively, the practical rule stays the same: put shared automation in #!/usr/bin/env bash or POSIX sh scripts, which both shells run as normal programs.
Customisation: abbreviations, prompts and plugins
Fish replaces most alias use with abbreviations. abbr -a gco git checkout expands gco into the full command as you press space or enter, so your history and screen show what actually ran. Abbreviations can match a regex and call a function, for example turning ... into cd ../../. Fish 4.9 lets them carry descriptions shown in the completion pager. Prompts are functions (fish_prompt and fish_right_prompt), and fish_config, either the web UI or the CLI, lets you preview and pick from bundled prompts and colour themes. Fish 4.8.1 added separate colours for builtins and functions. Vi key bindings are built in. Zsh's customisation is broader and lower-level. Its line editor exposes widgets you can bind to any key, region_highlight controls text attributes, and the completion system can be tuned per command and context, though the zsh FAQ itself calls the zshcompsys manual complicated. Aliases come in normal and global (alias -g) forms. The ecosystem is the real draw: Oh My Zsh's bundled plugins cover git, Docker, kubectl and most popular tools, and there are many plugin managers and prompt themes. Fish has third-party plugin managers and themes too, but far fewer, because more is built in. If you want a curated, batteries-included shell, fish wins. If you want to script your editor-like command line, zsh does.
Maturity, releases and platform availability
Zsh is the older and more conservative project. The zsh-users GitHub mirror shows 5.9 tagged on 14 May 2022, then bug-fix releases 5.9.1 on 31 May 2026 and 5.9.2 on 12 July 2026, whose README calls it a bug-fix release and notes PCRE support is now PCRE2. The master branch README already describes version 5.10 as a security and feature release with several incompatibilities. vi users will notice that the default keymap becomes emacs regardless of $EDITOR, and restricted mode is removed. As of November 2026, 5.10 has not been tagged. Zsh is preinstalled on macOS and packaged everywhere, and its permissive licence makes it easy for vendors to ship. Fish moves faster. The 4.0.0 release in February 2025 ported the core from C++ to Rust, and since then 4.1 through 4.9 have shipped roughly every one to two months, with 4.9.3 on 8 September 2026 the latest. Fish is mostly GPL-2.0, with some components under PSF, MIT and LGPL licences, and the repo has about 34k GitHub stars. It ships a macOS installer and app bundle, standalone Linux binaries for x86_64 and aarch64, and packages for the major distros, the BSDs, Cygwin, MSYS2 and WSL. Neither shell runs natively on Windows outside those environments. On a fresh server, zsh is the one more likely to be installed already, though fish is one package away.
Verdict
For a personal interactive shell, fish is the better default in 2026. You install it, set it as your shell, and immediately get autosuggestions, syntax highlighting, completions and readable configuration, with nothing to maintain. That is exactly what most people spend an afternoon assembling in zsh from Oh My Zsh, zsh-autosuggestions and zsh-syntax-highlighting. The Rust port in 4.0 and the steady 4.x releases show the project is in good health. The price is compatibility. Fish is deliberately not POSIX, so pasted Bash snippets with heredocs, subshells or $(( )) fail, and anything you want to share should still be written as a Bash or sh script with a proper shebang. That works fine in practice, since fish runs those scripts like any other program. Choose zsh if you constantly paste commands from Bash-oriented docs, if your team shares a common dotfiles repo, if you manage servers where fish is not installed, or if you want deep control over completion and key handling. It is also the zero-effort choice on macOS, where it is already the default. Start with a small, fast plugin set rather than a heavy framework if startup time matters to you.


