nvm — 在同一台机器上轻松切换 Node 版本
待复核nvm(Node Version Manager)是一个让你在同一台机器上装多个 Node.js 版本,并随时切换的工具。日常类比:像家里换灯泡——同一个灯座(你的电脑),可以换 5W、10W、20W 不同灯泡(不同 Node 版本),不用拆整盏灯。切换的开关其实是改 PATH:把「当前这盏灯」的目录排到命令查找列表最前面。
你敲:
nvm install 20 # 装 Node 20nvm install 18 # 再装一个 Node 18nvm use 18 # 当前终端切到 18node -v # → v18.x.xnvm 本身不是一个二进制,而是一个被 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你不知道是什么
-
靠 PATH 切换,不动系统 Node:每个版本装在
~/.nvm/versions/node/v20.10.0/这种独立目录里。nvm use 20只是把这个目录前置到PATH最前。 -
per-shell 生效,不是全局:A 终端
nvm use 18,B 终端依然是默认版本。这是 PATH 的天然属性——环境变量只对当前进程生效。 -
.nvmrc锁定项目版本:项目根目录放一个文件.nvmrc内容写18.17.1,团队每个人cd进来后跑nvm use就自动切到 18.17.1。CI 也读它。 -
bash 脚本,不是编译型:意味着每次开新 shell 都要 source 一遍
nvm.sh(约 20KB bash),冷启动可能加 100-300ms。
案例 1:装好后第一次用
Section titled “案例 1:装好后第一次用”curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash# 重开终端后nvm install --ltsnvm install 20nvm alias default 20node -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让以后新终端默认把该目录前置到PATH;node -v应显示 v20。
案例 2:项目级版本锁定
Section titled “案例 2:项目级版本锁定”cd my-projectecho "18.17.1" > .nvmrcnvm use# → Now using node v18.17.1逐部分解释:
.nvmrc只是一行版本号,约定「这个仓库用哪盏灯泡」。- 裸敲
nvm use(不带参数)会读当前目录的.nvmrc,再改本终端的PATH。 - 只影响当前 shell;隔壁终端若没
use,仍是 default。 - CI 里
actions/setup-node也可直接读.nvmrc,本地与流水线对齐。
案例 3:临时用某版本跑一次命令
Section titled “案例 3:临时用某版本跑一次命令”nvm exec 16 npm test逐部分解释:
exec不改当前 shell 的 default,只在子进程里把 Node 16 的目录塞进PATH。- 适合「只想确认 bug 在 16 上是否复现」,测完终端仍停在原来的版本。
- 对比:
nvm use 16会改当前终端,直到你再use别的版本。
-
shell 启动变慢:source
nvm.sh是 bash 脚本,开新终端冷启动加 100-300ms。重度用户用 lazy-load wrapper(在第一次调nvm时才真正 source)能缓解。 -
.nvmrc不会自动触发use:单纯cd进项目目录不会切版本,需要手敲nvm use,或在 zshchpwdhook 里挂自动切换。新人最常踩。 -
Homebrew 装的 nvm 不被官方支持:
brew install nvm装出来的版本路径与官方安装脚本不同,PATH 容易乱。官方文档明确说”用 curl 安装脚本,不要用 brew”。 -
~/.npmrc里写prefix会破坏 nvm:老教程会让你设 npm prefix,但这会让 npm 全局包装到 nvm 目录之外,切版本就找不到了。删掉 prefix 就行。 -
Windows 原生不支持:
nvm-sh/nvm只支持 macOS/Linux/WSL。Windows 用户要用名字像但完全独立的 nvm-windows(Go 写的),命令兼容但实现不同。
适用 vs 不适用场景
Section titled “适用 vs 不适用场景”适用:
- 个人开发,需要同时维护多个 Node 版本的项目
- 团队约定
.nvmrc锁版本 - 想试新版 Node 又不想覆盖系统版本
- macOS / Linux / WSL 环境
不适用:
- Windows 原生(用 nvm-windows 或 fnm)
- shell 启动速度敏感(fnm / volta 更合适,编译型二进制零启动开销)
- 项目级版本钉死且不想手敲
use(volta 在package.json里写volta.node自动钉死) - 容器化场景(直接
FROM node:20即可,不需要切换)
| 工具 | 实现 | 卖点 | 缺点 |
|---|---|---|---|
| nvm | bash 脚本 | 81k star 事实标准、生态最成熟 | shell 启动慢、Windows 不原生 |
| fnm | Rust 二进制 | 启动快 30-100 倍、兼容 .nvmrc | 较新、生态稍弱 |
| volta | Rust 二进制 | 项目级版本钉死,无需 use | 生态较小 |
| n | bash 脚本 | 最简单粗暴,直接装到 /usr/local | 不靠 PATH 切换,会污染系统 |
| asdf | bash 脚本 | 多语言版本管理(Node/Python/Ruby/…) | 配置复杂 |
零基础推荐:先 nvm 入门,遇到 shell 启动慢问题再换 fnm。
历史小故事(可跳过)
Section titled “历史小故事(可跳过)”- 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 发布,仍是事实标准。
- 环境变量
PATH是 shell 切版本的底层机制——nvm 只是给 PATH 操作套了个友好接口 - bash 脚本工具的代价:功能强但启动慢;现代趋势是用 Rust/Go 重写(fnm/volta)
- per-shell 生效不是 bug 是 feature:让你能在不同终端开不同版本同时工作
- 生态地位 ≠ 技术先进:nvm bash 实现并不”现代”,但 81k star 的工具链整合(CI、教程、IDE)让它依然是首选
- 官方仓库 README:nvm-sh/nvm(安装、命令、FAQ 都在这一页)
- 性能优化:lazy-load nvm 加快 shell 启动
- 替代方案:fnm / volta
- pnpm —— 包管理器层面的”按需安装”,与 nvm 在工具链光谱上互补
- homebrew —— macOS 包管理器;提示:不要用它装 nvm
- pnpm —— 同样属于 Node 工具链;nvm 管 Node 版本,pnpm 管包
- homebrew —— macOS 包管理器;nvm 官方反对用 brew 安装自己
- asdf —— nvm 的多语言泛化版本,能管 Python/Ruby/Erlang 等
- pyenv —— pyenv — 用 shim 把 python 命令拦截后路由到指定版本