跳转到内容

nvm — 在同一台机器上轻松切换 Node 版本

待复核

nvm(Node Version Manager)是一个让你在同一台机器上装多个 Node.js 版本,并随时切换的工具。日常类比:像家里换灯泡——同一个灯座(你的电脑),可以换 5W、10W、20W 不同灯泡(不同 Node 版本),不用拆整盏灯。切换的开关其实是改 PATH:把「当前这盏灯」的目录排到命令查找列表最前面。

你敲:

Terminal window
nvm install 20 # 装 Node 20
nvm install 18 # 再装一个 Node 18
nvm use 18 # 当前终端切到 18
node -v # → v18.x.x

nvm 本身不是一个二进制,而是一个被 source 进 shell 的 bash 脚本。它的全部魔法只是修改 PATH 环境变量,把”当前要用的 Node 版本”目录排在最前面。

GitHub 上有 81k star,是 Node 生态的事实标准。

不懂版本管理器,下面这些事都搞不定:

  • 老项目用 Node 14、新项目用 Node 20,不能切换就只能开两台机器
  • 团队 .nvmrc 写死了 18.17.1,本地用 20 跑出来的结果可能和 CI 不一致
  • 想试 Node 22 新特性,又怕装上去把工作搞挂
  • 看 GitHub issue 时别人贴 nvm use && npm test 你不知道是什么
  1. 靠 PATH 切换,不动系统 Node:每个版本装在 ~/.nvm/versions/node/v20.10.0/ 这种独立目录里。nvm use 20 只是把这个目录前置到 PATH 最前。

  2. per-shell 生效,不是全局:A 终端 nvm use 18,B 终端依然是默认版本。这是 PATH 的天然属性——环境变量只对当前进程生效。

  3. .nvmrc 锁定项目版本:项目根目录放一个文件 .nvmrc 内容写 18.17.1,团队每个人 cd 进来后跑 nvm use 就自动切到 18.17.1。CI 也读它。

  4. bash 脚本,不是编译型:意味着每次开新 shell 都要 source 一遍 nvm.sh(约 20KB bash),冷启动可能加 100-300ms。

Terminal window
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
# 重开终端后
nvm install --lts
nvm install 20
nvm alias default 20
node -v

逐部分解释:

  • 安装脚本把 nvm.sh 写进 ~/.nvm/,并在 ~/.bashrc / ~/.zshrc 里加一行 source
  • 新开终端时 shell 先 source nvm.sh,nvm 命令才可用。
  • nvm install 20 把 Node 解压到 ~/.nvm/versions/node/v20.x.x/,不碰系统 /usr/bin/node
  • nvm alias default 20 让以后新终端默认把该目录前置到 PATHnode -v 应显示 v20。
Terminal window
cd my-project
echo "18.17.1" > .nvmrc
nvm use
# → Now using node v18.17.1

逐部分解释:

  • .nvmrc 只是一行版本号,约定「这个仓库用哪盏灯泡」。
  • 裸敲 nvm use(不带参数)会读当前目录的 .nvmrc,再改本终端的 PATH
  • 只影响当前 shell;隔壁终端若没 use,仍是 default。
  • CI 里 actions/setup-node 也可直接读 .nvmrc,本地与流水线对齐。

案例 3:临时用某版本跑一次命令

Section titled “案例 3:临时用某版本跑一次命令”
Terminal window
nvm exec 16 npm test

逐部分解释:

  • exec 不改当前 shell 的 default,只在子进程里把 Node 16 的目录塞进 PATH
  • 适合「只想确认 bug 在 16 上是否复现」,测完终端仍停在原来的版本。
  • 对比:nvm use 16 会改当前终端,直到你再 use 别的版本。
  1. shell 启动变慢:source nvm.sh 是 bash 脚本,开新终端冷启动加 100-300ms。重度用户用 lazy-load wrapper(在第一次调 nvm 时才真正 source)能缓解。

  2. .nvmrc 不会自动触发 use:单纯 cd 进项目目录不会切版本,需要手敲 nvm use,或在 zsh chpwd hook 里挂自动切换。新人最常踩。

  3. Homebrew 装的 nvm 不被官方支持brew install nvm 装出来的版本路径与官方安装脚本不同,PATH 容易乱。官方文档明确说”用 curl 安装脚本,不要用 brew”。

  4. ~/.npmrc 里写 prefix 会破坏 nvm:老教程会让你设 npm prefix,但这会让 npm 全局包装到 nvm 目录之外,切版本就找不到了。删掉 prefix 就行。

  5. Windows 原生不支持nvm-sh/nvm 只支持 macOS/Linux/WSL。Windows 用户要用名字像但完全独立的 nvm-windows(Go 写的),命令兼容但实现不同。

适用

  • 个人开发,需要同时维护多个 Node 版本的项目
  • 团队约定 .nvmrc 锁版本
  • 想试新版 Node 又不想覆盖系统版本
  • macOS / Linux / WSL 环境

不适用

  • Windows 原生(用 nvm-windows 或 fnm)
  • shell 启动速度敏感(fnm / volta 更合适,编译型二进制零启动开销)
  • 项目级版本钉死且不想手敲 use(volta 在 package.json 里写 volta.node 自动钉死)
  • 容器化场景(直接 FROM node:20 即可,不需要切换)
工具实现卖点缺点
nvmbash 脚本81k star 事实标准、生态最成熟shell 启动慢、Windows 不原生
fnmRust 二进制启动快 30-100 倍、兼容 .nvmrc较新、生态稍弱
voltaRust 二进制项目级版本钉死,无需 use生态较小
nbash 脚本最简单粗暴,直接装到 /usr/local不靠 PATH 切换,会污染系统
asdfbash 脚本多语言版本管理(Node/Python/Ruby/…)配置复杂

零基础推荐:先 nvm 入门,遇到 shell 启动慢问题再换 fnm。

  • 2010 年:Tim Caswell 在 GitHub 发布第一版 nvm(在 Creationix 命名空间下)。当时 Node.js 才 1 岁,版本变化飞快,用户急需切换工具。
  • 2014 年:项目搬到 nvm-sh 组织,社区接管维护。
  • 2018 年:Schniz 发布 fnm(Fast Node Manager),Rust 实现,启动速度快 30-100 倍。
  • 2019 年:LinkedIn 团队发布 volta,主打项目级版本钉死。
  • 2026-01-29:nvm v0.40.4 发布,仍是事实标准。
  1. 环境变量 PATH 是 shell 切版本的底层机制——nvm 只是给 PATH 操作套了个友好接口
  2. bash 脚本工具的代价:功能强但启动慢;现代趋势是用 Rust/Go 重写(fnm/volta)
  3. per-shell 生效不是 bug 是 feature:让你能在不同终端开不同版本同时工作
  4. 生态地位 ≠ 技术先进:nvm bash 实现并不”现代”,但 81k star 的工具链整合(CI、教程、IDE)让它依然是首选
  • pnpm —— 同样属于 Node 工具链;nvm 管 Node 版本,pnpm 管包
  • homebrew —— macOS 包管理器;nvm 官方反对用 brew 安装自己
  • asdf —— nvm 的多语言泛化版本,能管 Python/Ruby/Erlang 等
  • pyenv —— pyenv — 用 shim 把 python 命令拦截后路由到指定版本