← 글 목록

notes

nvm

nvm으로 Node.js 버전 설치·전환·프로젝트별 관리하는 방법.


  • nvm은 Node 여러 버전을 깔아 두고 nvm use로 바꿔 끼는 도구다.
  • 프로젝트 루트의 .nvmrc에 버전을 적어 두면 nvm use 한 번으로 맞춰진다.
  • CI에서는 setup-node의 node-version-file로 같은 .nvmrc를 읽게 한다.

왜 쓰나

Node는 버전마다 동작이 조금씩 다르다. 회사 일이랑 개인 프로젝트를 같이 하다 보면 요구하는 버전이 꼭 갈린다.

nvm 없이 Node를 직접 깔아 쓰면 버전 바꿀 때마다 지웠다 깔았다 해야 한다. nvm을 쓰고 나서는 그게 명령어 한 줄이 됐다.

원리는 단순하다. 버전마다 ~/.nvm/versions/node/v20.x.x 같은 폴더에 따로 깔아 두고, nvm use를 하면 PATH 맨 앞을 그 버전의 bin 폴더로 바꿔 끼운다. 그래서 which node를 찍어 보면 경로가 ~/.nvm/versions/...로 나온다. 시스템에 깔린 Node는 건드리지 않는다.


비유


자주 쓰는 명령어

# 설치 가능한 버전 목록
nvm ls-remote

# 특정 버전 설치
nvm install 20
nvm install 18.19.0

# 지금 터미널에서 쓸 버전
nvm use 20

# 기본 버전 (새 터미널 열 때)
nvm alias default 20

# 설치된 버전 목록
nvm ls

# 현재 버전
node -v

.nvmrc — 프로젝트마다 버전 고정

프로젝트 루트에 .nvmrc 파일:

20

그 디렉터리에서:

nvm use    # .nvmrc 읽어서 자동 전환

팀원 모두 같은 Node 버전으로 맞출 때 쓴다. 숫자 말고 lts/*나 lts/iron 같은 별칭도 넣을 수 있다.

.nvmrc에 적힌 버전이 아직 안 깔려 있으면 nvm use는 에러를 내고 끝난다. 그때는 nvm install을 인자 없이 치면 .nvmrc를 읽어서 깔아 준다.

폴더 들어갈 때 자동으로 nvm use 하기 (zsh)

매번 nvm use 치기 귀찮아서 ~/.zshrc에 넣어 둔 훅이다. cd할 때마다 .nvmrc를 찾아서 버전을 맞추고, 없는 폴더로 나가면 default로 돌린다.

autoload -U add-zsh-hook
load-nvmrc() {
  local nvmrc_path
  nvmrc_path="$(nvm_find_nvmrc)"
  if [ -n "$nvmrc_path" ]; then
    local nvmrc_node_version
    nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")
    if [ "$nvmrc_node_version" = "N/A" ]; then
      nvm install
    elif [ "$nvmrc_node_version" != "$(nvm version)" ]; then
      nvm use
    fi
  elif [ -n "$(PWD=$OLDPWD nvm_find_nvmrc)" ] && [ "$(nvm version)" != "$(nvm version default)" ]; then
    nvm use default
  fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc

nvm vs npm vs pnpm (헷갈리기 쉬움)

nvm → Node 20 선택
  └→ pnpm install → node_modules 설치

macOS에서 설치 (요약)

공식 설치 스크립트 또는 Homebrew:

# curl 방식 (nvm 공식)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash

# 셸 설정 후
nvm install 20
nvm use 20

설치 스크립트가 ~/.zshrc에 아래 로딩 코드를 넣어 준다. 터미널을 새로 열었는데 nvm: command not found가 뜨면 대부분 이 줄이 빠졌거나 다른 rc 파일에 들어간 경우였다.

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

Homebrew로 깐 경우는 경로가 /opt/homebrew/opt/nvm/nvm.sh로 바뀐다. 다만 nvm 쪽에서 brew 설치는 공식 지원하지 않는다고 해서, 나는 curl 방식으로 깐다.


fnm / volta — nvm 대안

셋 다 하는 일은 같다. Node 버전 스위처다. 나는 익숙해서 nvm을 계속 쓰는데, 셸 시작이 느리다 싶으면 fnm으로 갈아타는 것도 괜찮다.


실무 팁

  • 모노레포는 루트 .nvmrc + engines in package.json으로 버전 맞추기
  • nvm use 안 하고 빌드 깨지면 → node -v 먼저 확인
  • global 패키지는 Node 버전마다 따로 설치됨 (npm i -g 한 번 더)
  • CI(GitHub Actions)는 nvm 대신 actions/setup-node로 같은 버전 지정
  • 새 버전으로 올릴 때 전역 패키지까지 옮기려면 nvm install 22 --reinstall-packages-from=20

CI에서도 같은 버전 쓰기

CI 러너에는 nvm이 없으니 setup-node가 .nvmrc를 직접 읽게 한다. 이렇게 해 두면 버전을 올릴 때 .nvmrc 한 군데만 고치면 로컬, 팀원, CI가 같이 따라온다.

- uses: actions/checkout@v4
- uses: actions/setup-node@v4
  with:
    node-version-file: '.nvmrc'
- run: node -v

package.json의 engines에도 "node": ">=20"처럼 적어 두면, 다른 버전으로 설치할 때 경고가 떠서 한 번 더 걸러진다.


요약

nvm은 Node 여러 버전을 깔아 두고 nvm use로 갈아 끼는 도구다. 프로젝트마다 Node 버전이 다르면 사실상 없으면 안 되는 도구라서, 새 맥을 세팅하면 제일 먼저 깐다.