How to Use NVM with Fish Shell
Install and configure nvm.fish to manage multiple Node.js versions in Fish Shell. Covers installation, switching versions, .nvmrc support, and default versions.
The original nvm (Node Version Manager) is a Bash script. It doesn’t work in Fish. If you try sourcing it in Fish, you get syntax errors because nvm relies on POSIX shell features that Fish deliberately doesn’t support.
The fix is nvm.fish — a separate Node version manager written entirely in Fish. Same concept (install and switch between Node versions), different implementation. It’s made by the same person who built Fisher, and it works well.
Install nvm.fish
You need Fisher first. If you don’t have it:
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher
Then install nvm.fish:
fisher install jorgebucaran/nvm.fish
That’s it. No additional configuration needed. Restart your shell or open a new terminal tab.
Install Node versions
# Install the latest release
nvm install latest
# Install the latest LTS version
nvm install lts
# Install a specific version
nvm install 22
nvm install 20.11.0
nvm install v18.19.1
# Install an LTS line by codename
nvm install iron # Node 20 LTS
nvm.fish downloads pre-built Node binaries and stores them in ~/.local/share/nvm/ (following the XDG Base Directory spec). Each version gets its own directory.
Switch between versions
# Use a specific version (current session only)
nvm use 22
nvm use lts
nvm use latest
# Check which version is active
nvm current
# List installed versions
nvm list
nvm use changes the active Node version for your current shell session. Open a new terminal and it reverts to the default (or whatever .nvmrc specifies for that directory).
Set a default Node version
Without a default, new shell sessions won’t have any nvm-managed Node on the PATH. Set one with a universal variable:
set --universal nvm_default_version v22
Now every new Fish session starts with Node 22 active. You can use lts, latest, or a specific version number.
Automatic version switching with .nvmrc
This is the feature I use most. Create a .nvmrc file in a project’s root directory:
echo "20" > ~/projects/legacy-app/.nvmrc
echo "22" > ~/projects/new-app/.nvmrc
When you cd into a directory with a .nvmrc (or .node-version) file, nvm use reads it automatically. This works by traversing up the directory tree until it finds the file.
cd ~/projects/legacy-app
node --version # v20.x.x
cd ~/projects/new-app
node --version # v22.x.x
.nvmrc formats
nvm.fish supports the same .nvmrc formats as the original nvm: version numbers (20, 20.11, 20.11.0), lts, latest, and LTS codenames (iron, hydrogen). Files named .node-version work too.
Install default global packages
If you want certain npm packages installed every time you install a new Node version:
set --universal nvm_default_packages yarn typescript tsx
Now nvm install 22 will also run npm install -g yarn typescript tsx after downloading Node.
Uninstall Node versions
nvm uninstall v18
nvm uninstall 20.11.0
This removes the installed binaries from the nvm data directory.
Change the install mirror
If you need to use a mirror (corporate proxy, China mirror, etc.):
set --universal nvm_mirror https://npmmirror.com/mirrors/node
Default is https://nodejs.org/dist.
Change the data directory
By default, nvm.fish stores everything in ~/.local/share/nvm/. Change it with:
set --global nvm_data ~/.nvm
If you previously used the Bash-based nvm and have Node versions in ~/.nvm/, this lets nvm.fish use that same directory. Versions installed by either tool should work.
nvm.fish vs nvm (the Bash version)
| nvm.fish | nvm (Bash) | |
|---|---|---|
| Shell support | Fish only | Bash, Zsh |
| Written in | Fish | Bash/POSIX sh |
| Installation | Fisher plugin | curl script |
| Startup impact | Minimal (lazy loading) | Can add 200-500ms |
.nvmrc support | Yes | Yes |
| Tab completions | Yes (Fish native) | Basic |
| LTS codenames | Yes | Yes |
The performance difference is worth mentioning. The Bash-based nvm is notorious for slow shell startup because it needs to be sourced in every new session. nvm.fish loads lazily — it only activates when you actually run nvm or switch to a directory with .nvmrc. You won’t notice it in your startup time.
nvm.fish vs fnm vs Volta
There are other Node version managers that work with Fish:
fnm (Fast Node Manager) — written in Rust, works with any shell. It’s faster than nvm.fish for installs because it uses parallel downloads. Install with brew install fnm or cargo install fnm, then add fnm env --use-on-cd --shell fish | source to your config.fish.
Volta — also Rust-based, also cross-shell. Its main differentiator is per-project global package management. Install with curl https://get.volta.sh | bash, then add set -gx VOLTA_HOME ~/.volta; fish_add_path $VOLTA_HOME/bin to config.fish.
I use nvm.fish because it’s pure Fish, integrates with Fisher, and I don’t need the extra features of fnm or Volta. If you use multiple shells, fnm or Volta are better choices since they work everywhere.
Troubleshooting
nvm: command not found — Fisher didn’t install correctly, or your shell hasn’t reloaded. Run fisher list to check if jorgebucaran/nvm.fish appears. Try opening a new terminal.
Node not found after install — Make sure you ran nvm use <version> after installing. Or set a default version: set --universal nvm_default_version lts.
.nvmrc not being read automatically — nvm.fish reads .nvmrc when you run nvm install or nvm use without arguments. For automatic switching on cd, make sure you’re using a recent version of nvm.fish (fisher update jorgebucaran/nvm.fish).
Related guides
- Install Fish Shell on Ubuntu — get Fish set up first
- Fish Shell on macOS — Mac setup including Homebrew Node
- Best Fish Shell plugins — nvm.fish and other recommended plugins
- Fish Shell functions guide — create your own Node-related helper functions