The first time you use Fish, you’ll wonder why other shells don’t even ship with autocomplete by default.
Fish (Friendly Interactive Shell) is a shell designed for interactive use. It comes with syntax highlighting, autosuggestions, and fuzzy search built-in—no need to install Oh-My-Zsh and dozens of plugins like with Zsh.
Installation#
NixOS:
users.defaultUserShell = pkgs.fish;
programs.fish.enable = true;Or via Home Manager:
programs.fish = {
enable = true;
interactiveShellInit = ''
set -g fish_greeting
'';
};Why Switch from Zsh to Fish#
| Feature | Zsh (default) | Fish (default) |
|---|---|---|
| Syntax highlighting | ❌ Needs plugin | ✅ Built-in |
| Autosuggestions | ❌ Needs plugin | ✅ Built-in |
| Fuzzy completion | ❌ Needs plugin | ✅ Built-in |
| Man page completion | ❌ | ✅ Auto-generated |
| Config syntax | Bash compatible | Clean and intuitive |
| Startup speed | Slow (many plugins) | Fast |
Fish’s philosophy is “the default should be the best.”
Daily Usage#
Autosuggestions#
As you type, Fish shows suggestions in grey based on history and context:
$ git comm
↑ grey text: "git commit -m "
→ Press → or Ctrl+F to acceptTab Completion#
Press Tab to list all options, with fuzzy matching:
$ cd pro<Tab>
projects/ proposals/ prometheus/Syntax Highlighting#
Valid commands are green, invalid ones red. Existing paths are blue, non-existent ones have red underlines:
$ ech hello # "ech" in red (command not found)
$ cat /tmp/test # "/tmp/test" underlined red (file doesn't exist)Configuration#
Fish config lives in ~/.config/fish/:
~/.config/fish/
├── config.fish # Main config
├── conf.d/ # Auto-loaded scripts
│ ├── abbr.fish
│ ├── aliases.fish
│ └── path.fish
└── functions/ # Custom functionsMy config.fish#
# Remove greeting
set -g fish_greeting
# Environment variables
set -gx EDITOR emacsclient -c
set -gx VISUAL emacsclient -c
set -gx LANG en_US.UTF-8
# PATH
fish_add_path ~/.cargo/bin
fish_add_path ~/.local/bin
fish_add_path /nix/var/nix/profiles/default/binAbbreviations vs Aliases#
Fish recommends abbr over alias because abbreviations expand as you type, so you can see the actual command:
abbr -a g git
abbr -a ga 'git add'
abbr -a gc 'git commit'
abbr -a gp 'git push'
abbr -a gs 'git status'
abbr -a l 'ls -la'
abbr -a .. 'cd ..'
abbr -a ... 'cd ../..'Effect: Type gs, press space, it auto-expands to git status.
Custom Functions#
# ~/.config/fish/functions/ll.fish
function ll
ls -lah $argv
end# ~/.config/fish/functions/mkcd.fish
function mkcd
mkdir -p $argv[1]
cd $argv[1]
endNixOS-specific Tips#
Auto-detect nix-shell#
# config.fish
if test -n "$IN_NIX_SHELL"
set -g fish_greeting "📦 nix-shell"
enddirenv + nix-direnv#
# home.nix
programs.direnv = {
enable = true;
nix-direnv.enable = true;
};Automatically loads dev environment when entering a directory with .envrc, unloads when leaving.
Bash Incompatibility Notes#
Fish syntax differs from Bash. For scripts, it’s recommended to:
- Use
#!/usr/bin/env bashin script shebangs — keep writing scripts in Bash - Use Fish only for interactive use — don’t write scripts in Fish
- When copy-pasting Bash commands from the web — most simple commands work, complex pipes may need tweaking
Summary#
If you’re tired of configuring Zsh, Fish is the most hassle-free choice. It won’t turn you into a “shell config expert,” but it will make you slightly happier every time you open a terminal.
The NixOS Toolchain series wraps up here for now. Next up might be some specific Nix configuration tips.