Skip to content
Dev Tools Beginner Tutorial

Managing Multiple Node Versions with nvm

Install nvm, pin a Node version per project with .nvmrc, and stop fighting global-install conflicts—all from the terminal.

AI
DevClubHouse Curation
Jun 8, 2026 · 7 min read · 0 comments

What you'll build / learn

By the end of this tutorial you'll have nvm (Node Version Manager) installed, you'll switch between Node.js versions with a single command, pin a per-project version using a .nvmrc file, and understand why globally installed packages cause headaches—and how to avoid them.

Prerequisites

  • macOS or Linux. nvm is a shell script and does not run on native Windows. On Windows, either use nvm-windows (a separate project with different commands) or run nvm inside WSL2.
  • A bash or zsh shell. On modern macOS the default is zsh; most Linux distros default to bash. Check with echo $SHELL.
  • curl installed (preinstalled on macOS and most Linux).
  • No existing Node.js installed via a system package manager (Homebrew, apt, the official .pkg). Mixing those with nvm causes confusing PATH conflicts. If you have one, uninstall it first.

Step 1: Install nvm

nvm is distributed as an install script. Run the official installer (this does not require sudo):

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash

If you prefer to read the script before running it (a good habit), open the URL in your browser first, or download it and inspect it:

curl -o nvm-install.sh https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh
less nvm-install.sh
bash nvm-install.sh

The installer clones nvm into ~/.nvm and appends a few lines to your shell profile (~/.zshrc, ~/.bashrc, or ~/.bash_profile) that load nvm in new shells.

Step 2: Activate nvm in your current shell

The install script only edits your profile; it doesn't reload it. Either open a new terminal window, or run:

source ~/.zshrc   # if you use zsh
# or
source ~/.bashrc  # if you use bash

Confirm nvm is available:

command -v nvm

Expected output: nvm. Note that nvm is a shell function, not a binary, so which nvm may return nothing—use command -v nvm instead.

Step 3: Install Node.js versions

Install the latest Long Term Support (LTS) release—the safe default for most projects:

nvm install --lts

Install a specific major version (nvm picks the newest matching release):

nvm install 20

List what you have installed locally:

nvm ls

List everything available to download:

nvm ls-remote

Step 4: Switch versions and set a default

Switch the current shell to a version:

nvm use 20
node --version   # -> v20.x.x

nvm use only affects the terminal session you run it in. To choose which version new terminals start with, set a default alias:

nvm alias default 20

Now every new shell will start on Node 20.

Step 5: Pin a version per project with .nvmrc

Instead of remembering which version each project needs, commit a .nvmrc file in the project root. From inside your project folder:

cd ~/code/my-app
node -v > .nvmrc

That writes the exact version (e.g. v20.11.1). For a more flexible file you can pin just the major line—edit .nvmrc to contain a single line:

20

Now anyone (including you on a new machine) can match the project's Node version:

nvm use      # reads .nvmrc, switches to that version
nvm install  # reads .nvmrc, installs it if missing

Commit .nvmrc to git so the whole team stays in sync:

git add .nvmrc
git commit -m "Pin Node version with .nvmrc"

Optional: auto-switch when you cd

nvm doesn't auto-switch by default. The official README provides a shell hook for zsh and bash that runs nvm use automatically when you enter a directory containing .nvmrc. See the "Deeper Shell Integration" section of the nvm README for the exact snippet to add to your profile.

Step 6: Avoid global-install headaches

Here's the trap: each Node version installed by nvm has its own separate set of global packages. Install a CLI globally under Node 20, switch to Node 18, and that command vanishes from your PATH.

Best practices that sidestep this entirely:

Instead of… Do this Why
npm install -g some-cli npx some-cli Runs a one-off without installing globally
Relying on a global tool in a project Add it to devDependencies and run via npm scripts Version is pinned and reproducible per project
Reinstalling globals after each switch nvm install 22 --reinstall-packages-from=20 Copies globals from one version to another during install

For a project dependency, prefer:

npm install --save-dev eslint
npx eslint .

This keeps tools tied to the project and its Node version, so switching versions never breaks your workflow.

Verify it works

Run this sequence to confirm everything is wired up:

nvm --version          # prints e.g. 0.40.1
nvm ls                 # lists installed versions, '->' marks the active one
node --version         # current Node version
nvm install 18         # add another version
nvm use 18 && node -v  # -> v18.x.x
nvm use 20 && node -v  # -> v20.x.x

If each node -v reflects the version you just selected, nvm is working correctly.

Troubleshooting

nvm: command not found in a new terminal. Your profile isn't loading nvm. Confirm the loader block exists in ~/.zshrc or ~/.bashrc:

grep -n NVM_DIR ~/.zshrc ~/.bashrc 2>/dev/null

If it's missing, reinstall (Step 1) or add it manually. If it's present, run source ~/.zshrc.

node still points to an old Homebrew/system version. Run command -v node. If the path isn't under ~/.nvm/, a system install is shadowing nvm. Uninstall it (brew uninstall node) and reopen your terminal.

nvm use says "No .nvmrc file found." You're not in the project directory, or the file is missing/misnamed. Check with cat .nvmrc and ensure it's named exactly .nvmrc in the current folder.

A global CLI disappeared after switching versions. That's expected behavior—globals are per-version. Reinstall it under the active version, or better, run it with npx or add it as a project devDependency.

Next steps

  • Read the nvm README for shell auto-switching and CI usage.
  • Explore Corepack to pin npm, pnpm, or yarn versions per project alongside Node.
  • For teams that want language-agnostic version pinning, look at asdf or mise as alternatives to nvm.

Discussion 0

Join the discussion

Sign in with GitHub to comment and vote.

Sign in with GitHub

No comments yet

Be the first to weigh in.

Related Reading