Daily-It

개발, AI, 인프라, 자동화와 일상 IT 제품 후기를 직접 써보며 정리하는 기술 블로그입니다.

Installing NVM on Apple Silicon Mac: Node.js Version Management Guide

Summary

Installing nvm on an Apple Silicon Mac is usually not hard, but the confusing part starts after the install: nvm: command not found, VS Code using a different Node version, Homebrew’s Node taking priority, or an old project requiring Node 14 on an arm64 machine.

The practical approach is simple. Install nvm with the official script, load it from the right zsh profile, install the Node.js LTS version you need, and commit a .nvmrc file per project. If something looks wrong, check the shell, the CPU architecture, and the actual Node path before reinstalling everything.

In this article

Why Node version management matters on Mac

Node.js version problems appear more often than they should. One project may still run on Node 18, while a new project expects Node 22 or 24. If you rely on one system-wide Node installation, npm install may succeed but the build can fail, or the build may pass while a package behaves differently at runtime.

nvm, short for Node Version Manager, lets you switch Node.js versions per project:

# Project A
nvm use 18

# Project B
nvm use 24

For Apple Silicon Macs, the main points are zsh configuration, arm64 support, and old Node versions that may still require Rosetta or an x86_64 environment.

Sources checked for this guide

The Korean source article was revised against official and version-specific sources. The same facts are preserved here.

Source What was checked
nvm official README Install script, zsh loading code, .nvmrc, LTS commands, Homebrew notice
nvm GitHub Releases Latest nvm release used in this article: v0.40.5
Node.js downloads and release pages LTS, Current, Maintenance LTS, and EOL concepts
Apple Support zsh as the default shell since macOS Catalina
Homebrew documentation Apple Silicon Homebrew path: /opt/homebrew
Volta and fnm docs Alternative Node version managers

Install nvm and set up Node.js

Step 1. Check your shell and CPU architecture

On modern macOS, the default shell is usually zsh. Check it first:

echo $SHELL

A typical result is:

/bin/zsh

Then check the CPU architecture:

uname -m

On Apple Silicon, this usually returns:

arm64

If you see zsh and arm64, most of the setup below should be read as a ~/.zshrc-based setup.

Step 2. Install nvm with the official script

Use the official nvm install script. At the time checked for the Korean source, the current nvm release is v0.40.5.

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

If your environment uses wget, this form is also available:

wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash

The installer usually creates ~/.nvm and adds nvm loading lines to a shell profile.

Step 3. Reload zsh or reopen the terminal

If nvm does not work immediately after installation, do not reinstall first. In many cases, the shell profile has simply not been reloaded yet.

source ~/.zshrc

Or close the terminal completely and open it again. Then verify nvm like this:

command -v nvm

This is normal:

nvm

Step 4. Check the zsh loading lines

Your ~/.zshrc should contain the nvm loading code. A common setup is:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

The nvm README also documents an $XDG_CONFIG_HOME-aware variant:

export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

For a personal Mac development machine, the first version is often enough. If your company manages shared dotfiles or shell profiles, check the second style as well.

Step 5. Install Node.js LTS

For a new project, starting with the LTS line is usually the safest default:

nvm install --lts

Check the installed versions:

node -v
npm -v

To make the currently selected latest Node the default:

nvm alias default node

To pin a specific major version as the default:

nvm alias default 24

Step 6. Add a project-specific .nvmrc

For real projects, this is the most useful part. Put a .nvmrc file at the project root so every developer can use the same Node version.

For a Node 24 project, the file can simply contain:

24

To follow the latest LTS line, you can use:

lts/*

Then run this in the project directory:

nvm install
nvm use

A README can keep the onboarding sequence short and clear:

nvm install
nvm use
npm install

A committed .nvmrc prevents many “works on my machine” build problems caused by mismatched Node versions.

Step 7. Optional: automatically run nvm use when changing directories

If you do not want to type nvm use manually, you can add a zsh hook:

autoload -U add-zsh-hook

load-nvmrc() {
  local node_version="$(nvm version)"
  local nvmrc_path="$(nvm_find_nvmrc)"

  if [ -n "$nvmrc_path" ]; then
    local nvmrc_node_version="$(nvm version "$(cat "$nvmrc_path")")"

    if [ "$nvmrc_node_version" = "N/A" ]; then
      nvm install
    elif [ "$nvmrc_node_version" != "$node_version" ]; then
      nvm use
    fi
  elif [ "$node_version" != "$(nvm version default)" ]; then
    nvm use default
  fi
}

add-zsh-hook chpwd load-nvmrc
load-nvmrc

This is optional. Some developers dislike the extra output or startup delay, so it is better as a personal preference than a forced team rule.

When Rosetta matters on Apple Silicon

If you use a current Node.js LTS release, Rosetta is usually not the first thing to worry about. According to the nvm documentation, Node.js provides Apple Silicon arm64 Darwin binaries starting with Node.js v16.0.0.

Node.js version Meaning on Apple Silicon
Node.js 16 and newer arm64 Darwin binaries are available
Node.js 14.17 and newer Experimental arm64 support is mentioned for source builds
Older Node.js 14 and below Rosetta 2 or an x86_64 environment may be required

Check the Node runtime architecture:

node -p "process.arch"

On an arm64 Node runtime, this prints:

arm64

Should you install nvm with Homebrew?

For nvm specifically, the safer answer is no. The nvm README states that Homebrew installation is not supported. If you run into nvm issues, the official project usually points you back to the official install-script method.

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

Homebrew is convenient for many development tools. For nvm, following the official install path avoids one common source of confusion.

nvm vs Volta vs fnm

nvm is not the only Node version manager. If you are choosing a team standard from scratch, Volta and fnm are worth comparing.

Tool Characteristics Good fit
nvm Widely used shell-based Node version manager When existing docs and .nvmrc compatibility matter
Volta Strong at pinning Node, npm, yarn, and pnpm tool versions When a team wants stricter JavaScript tooling consistency
fnm Rust-based, fast, and supports .nvmrc When you want nvm-like behavior with faster startup

For a personal development setup, nvm is still a reasonable starting point. For a team, the tool matters less than documenting the Node version in README and matching CI with local development.

Best practices for projects and teams

Commit .nvmrc

A .nvmrc file is small but valuable. Front-end and Node backend projects often fail because one developer is on a different Node major version.

24

Place it at the project root and commit it to Git.

Document the first-run commands

Make the first run obvious in README:

nvm install
nvm use
npm install
npm run dev

This removes guesswork during onboarding.

Match CI and local Node versions

If local development uses Node 24 but CI uses Node 20, results may differ. Match GitHub Actions, Jenkins, or other CI settings with the version in .nvmrc.

Leave a reason for old Node versions

If a project must stay on Node 14 or 16, write down why. A note about package compatibility or production constraints is much more useful than “we have always used it this way.”

Common mistakes

Using which nvm as the main check

nvm is loaded as a shell function, not a normal standalone executable. Prefer:

command -v nvm

Putting the loading code in the wrong profile file

The installer may choose one of ~/.bashrc, ~/.bash_profile, ~/.zshrc, or ~/.profile. On a zsh-based Mac, check ~/.zshrc first.

grep NVM_DIR ~/.zshrc

Mixing Homebrew Node and nvm Node without noticing

If Node was previously installed with brew install node, your PATH may still pick up the Homebrew binary.

which node
node -v

When nvm is active, the path usually contains .nvm:

/Users/your-name/.nvm/versions/node/v24.x.x/bin/node

Creating .nvmrc but never running nvm use

A .nvmrc file is a version marker. It does not automatically switch Node unless you add an auto-switch hook.

nvm use

Assuming VS Code and Terminal load the same shell profile

VS Code’s integrated terminal can use a different default profile. Compare the output in VS Code and in the normal Terminal app:

echo $SHELL
command -v nvm
node -v

Failure cases and fixes

Case 1. nvm: command not found after installation

This is the classic failure. It is often not a failed install; the shell profile has not been loaded.

source ~/.zshrc
command -v nvm

If nothing is printed, check the loading lines:

grep NVM_DIR ~/.zshrc

If they are missing, add:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

Then reload:

source ~/.zshrc

Case 2. nvm works in Terminal but not in VS Code

Check these commands inside VS Code first:

echo $SHELL
command -v nvm
node -v

Run the same commands in the normal Terminal app and compare. If they differ, use VS Code’s Terminal: Select Default Profile and confirm that zsh is used and ~/.zshrc is loaded.

Case 3. Homebrew Node is used instead of nvm Node

Do not look only at node -v. Check the actual binary path:

which node
node -v
npm -v

A nvm-managed Node normally looks like:

/Users/your-name/.nvm/versions/node/v24.x.x/bin/node

On Apple Silicon, a Homebrew Node often appears under:

/opt/homebrew/bin/node

If you plan to use nvm for per-project versions, run:

nvm use
which node

You do not always have to remove Homebrew Node, but you should know which Node your shell is actually running.

Case 4. .nvmrc exists but Node does not switch automatically

This is expected. .nvmrc records the project’s intended Node version. It does not switch by itself.

nvm install
nvm use

If you want automatic switching, add the zsh hook shown above. For teams, it is usually better to document the commands than to require everyone to use the same hook.

Case 5. Old Node installation fails on Apple Silicon

Current LTS versions usually work well on arm64. The problem is old Node versions. nvm documents arm64 Darwin binaries from Node.js v16.0.0, while older Node versions may need Rosetta or an x86_64 environment.

uname -m
node -p "process.arch"

If possible, upgrade the project to a supported LTS line. If an old version is truly required, write the reason in README so the next developer does not rediscover the same limitation.

Conclusion

nvm on Apple Silicon is mostly a shell and path problem, not a complicated Node problem. Install nvm through the official script, confirm zsh loads it, and verify the actual Node path with which node.

For personal projects, nvm is enough to start. For team projects, commit .nvmrc, document nvm install and nvm use, and keep CI on the same Node version. That small setup prevents many avoidable install and build errors.

References

Original Korean version: This article is based on the Korean version and lightly adapted for English readers.
Read the original Korean post.

Please show some love to Korean, too.