nvm — 在同一台机器上轻松切换 Node 版本
是什么
nvm(Node Version Manager)是一个让你在同一台机器上装多个 Node.js 版本,并随时切换的工具。日常类比:像家里换灯泡——同一个灯座(你的电脑),可以换 5W、10W、20W 不同灯泡(不同 Node 版本),不用拆整盏灯。
你敲:
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:装好后第一次用
# 装 nvm(一次性)curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
# 重开终端后nvm install --lts # 装最新 LTSnvm install 20 # 装 Node 20nvm ls # 列已装版本nvm alias default 20 # 把 20 设为新终端的默认案例 2:项目级版本锁定
cd my-projectecho "18.17.1" > .nvmrc # 团队约定用 Node 18.17.1nvm use # nvm 读 .nvmrc 自动切# 输出:Now using node v18.17.1CI 里也能用:GitHub Actions 的 actions/setup-node 直接读 .nvmrc,零配置。
案例 3:临时用某版本跑一次命令
nvm exec 16 npm test # 当前 shell 不切,用 16 跑一次 test适合”我只想验证下这个 bug 在 Node 16 上是否存在”的快速检查。
踩过的坑
-
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 不适用场景
适用:
- 个人开发,需要同时维护多个 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。
历史小故事(可跳过)
- 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 等
反向链接
- mach-vm-1987 —— Mach VM — 把虚拟内存抽象成”对象”,与硬件解耦
- openrct2 —— OpenRCT2 — 把一款 x86 汇编游戏彻底用 C++ 重写
- persistent-memory-2014 —— PMFS — 第一个为字节寻址持久内存设计的文件系统
- pnpm —— pnpm — 全机器只存一份的 Node 包管理器
- pyenv —— pyenv — 用 shim 把 python 命令拦截后路由到指定版本
- react-server-components —— React Server Components — 让组件自己决定在哪台机器跑