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.

How to Use NVM with Fish Shell

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.fishnvm (Bash)
Shell supportFish onlyBash, Zsh
Written inFishBash/POSIX sh
InstallationFisher plugincurl script
Startup impactMinimal (lazy loading)Can add 200-500ms
.nvmrc supportYesYes
Tab completionsYes (Fish native)Basic
LTS codenamesYesYes

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).