做前端或者 Node.js 后端开发的,应该都遇到过这种尴尬:手上维护的老项目锁在 Node 12 时代,新项目一上来就要 Node 20+,有些环境甚至要求 Node 14 和 Node 16 并存。手动去官网下载安装包来回替换?装一次就得配一次环境变量,改一次 PATH,稍不留神就把系统搞乱。npm 全局包更是重灾区,版本一换,全局包路径全乱,项目跑起来各种报错。
我第一次被这个问题折磨透,是在一个 Monorepo 项目里:子模块 A 必须用 Node 14.17,子模块 B 要求 Node 16.x,CI 上倒是无所谓,但本地联调时我只能反复卸载、安装,一天能折腾三回。直到我把nvm(Node Version Manager)的安装和使用彻底搞清楚,这件事才算真正解决。这篇教程不跟你讲虚的,直接把我从 Windows 到 macOS 的完整折腾过程、配置细节、踩过的坑全部摊开,保证你照着做就能在自己的机器上顺畅切换 Node 版本,顺手把 npm 全局包、pnpm、镜像源这些配套问题一次搞定。
1. 为什么需要 nvm:Node 版本管理的核心痛点
1.1 多项目 Node 版本冲突的真实场景
先看几个我实际遇到过的场景,你大概率也见过其中一个:
- 公司老后台系统用的 egg.js,只能在 Node 12 下跑,切到 Node 18 直接引入报错,连启动都起不来。
- 某个开源项目 clone 下来,package.json 里 engines 字段写着
"node": ">=16 <17",而你的机器是 Node 20,npm install 能跑,但编译原生模块时 node-gyp 崩溃。 - 你用 Node 18 全局安装了某个 CLI 工具,切到另一个 Node 版本后,命令直接消失。
- 团队其他人用了 Node 16 的
--experimental-fetch,而你还在 Node 14 下,同样的代码行为完全不一样。
这些问题本质上是同一个:Node.js 版本与项目依赖、原生模块编译、语法特性强耦合。没有版本管理工具时,你只能在系统层面装一个 Node,改版本就是卸载重装,改环境变量,既慢又容易出错。nvm 就是来解决这个问题的。
nvm 最大的价值不是“装很多个 Node”,而是“按需切换、互不干扰、一行命令搞定”。它可以在你的用户目录下安装多个互相隔离的 Node 版本,使用时通过命令动态切换当前终端生效的版本,切换成本几乎是零。
1.2 nvm 的工作原理与同类方案对比
nvm 的原理说起来其实很简单:平时我们执行node命令,系统是在 PATH 环境变量里找一个叫node的可执行文件。nvm 做的事情就是把当前要激活的 Node 版本所在的目录插入到 PATH 最前面,这样你敲node时命中的就是指定版本。
macOS / Linux 版的 nvm 是切换 PATH;Windows 上的 nvm-windows 更特殊一点:它会在NVM_SYMLINK指定的位置创建一个符号链接(默认是C:\Program Files\nodejs),切换版本时把这个链接重新指向当前版本目录。这也是为什么 Windows 上很多教程让你把 nodejs 链接目录加进 PATH,而不是真实版本目录。
同类方案我还对比过几个:
| 方案 | 跨平台 | 版本隔离方式 | 上手难度 | 适合场景 |
|---|---|---|---|---|
| nvm(mac/Linux 原生) | 仅 mac/Linux | 改 PATH | 低 | 绝大多数开发者日常使用 |
| nvm-windows | Windows | 符号链接 + PATH | 低 | Windows 下的主流选择 |
| n(tj 写的) | 仅 mac/Linux | 直接替换 /usr/local/bin 下文件 | 低 | 追求极简、单用户机器 |
| Volta | 全平台 | 在项目级固定工具链 | 中 | 团队协作、项目级锁定版本 |
| fnm(Rust 写的) | 全平台 | 改 PATH | 中 | 追求安装速度、Shell 启动速度 |
我个人的建议是:Windows 直接上 nvm-windows,macOS 用原生 nvm,Linux 同理。Volta 也很好,但它更偏向“项目级自动切换”,团队协作时比较香;如果你主要是本地多版本并存、临时切来切去,nvm 足够稳,生态也最成熟,网上遇到问题能找到的答案也最多。
2. 安装前的准备与详细安装步骤
2.1 安装前必做:彻底清理旧 Node 环境
这一步最容易忽略,但恰恰决定你后面能不能少踩坑。如果你电脑上已经装了 Node.js(不管是安装包装的还是 Homebrew 装的),装 nvm 之前最好先卸载干净。
为什么?因为 nvm(尤其是 Windows 版)依赖 PATH 顺序和符号链接。旧 Node 装在系统目录(比如C:\Program Files\nodejs),卸载不干净会出现两种情况:
- 你在 nvm 里切了版本,但终端跑
node -v还是旧版本,因为旧版本的路径排在前面,优先被系统找到了。 - 旧版本残留的 npm 全局包目录和 nvm 的符号链接路径冲突,导致全局命令认不出。
正确的清理步骤(Windows):
- 打开“设置 -> 应用 -> 已安装的应用”,卸载 Node.js,npm 一般会跟着卸掉。
- 手动删除 Node 安装目录,通常就是
C:\Program Files\nodejs(如果还在的话)。 - 检查并清理 npm 的缓存目录(默认在
C:\Users\你的用户名\AppData\Roaming\npm和C:\Users\你的用户名\AppData\Local\npm-cache),有就删掉。 - 打开环境变量编辑器(Win + R 输入
sysdm.cpl,切到“高级”选项卡,点“环境变量”),把 Path 里和 node、npm 相关的条目全部删掉。
macOS 上用 Homebrew 装的,就执行:
brew uninstall --ignore-dependencies node brew uninstall --force node顺手把~/.npmrc、~/.node-gyp、~/Library/Caches/npm这些残留目录清掉。不清理的话,后面装某些带原生模块的包时,node-gyp 可能还会引用旧的文件,报一些很诡异的错。
2.2 Windows 平台安装 nvm-windows
Windows 下大家用的都是nvm-windows,这个项目和 macOS 的 nvm 作者并不是同一个人,但功能体验高度一致,所以平时大家都直接叫它 nvm。
第一步,去 GitHub 上找coreybutler/nvm-windows的 releases 页面,下载nvm-setup.exe。这里有个小讲究:下载 installer 而不是 zip 绿色版。installer 会自动帮你写好环境变量和目录结构,绿色版虽然免安装,但手动配置时容易出错,对新手不友好。
双击安装时,安装路径选择有讲究,不要选带空格的路径,也不要用默认的C:\Program Files\nvm。原因有两个:
- Program Files 目录权限受限,后面 nvm 创建符号链接时可能会因为权限不足失败。
- 路径带空格,某些旧版 npm 脚本解析路径时会出问题。
我自己的安装路径是C:\dev\nvm,nodejs 符号链接路径是C:\dev\nodejs。你也可以用D:\nvm、F:\nvm这类目录,只要保证路径里没有空格、没有中文就行。
安装完打开系统环境变量,会看到多出来两个变量:
NVM_HOME:指向 nvm 安装目录,例如C:\dev\nvmNVM_SYMLINK:指向 nodejs 符号链接目录,例如C:\dev\nodejs
同时 Path 里会自动加上%NVM_HOME%和%NVM_SYMLINK%。安装包还自动生成了一份settings.txt,内容大概是:
root: C:\dev\nvm path: C:\dev\nodejs node_mirror: https://nodejs.org/dist/ npm_mirror: https://github.com/npm/cli/archive/这root和path就是上面两个环境变量的来源。node_mirror和npm_mirror是下载节点和 npm 包的镜像地址,默认走官方,国内用户一般要换成国内镜像,这个放到后面“加速下载”部分详细说。
安装完成后,打开一个新的终端窗口(旧的终端环境变量没刷新,直接敲 nvm 会提示找不到),执行:
nvm version能输出版本号,说明 nvm-windows 安装成功了。
2.3 macOS / Linux 平台安装 nvm
macOS 和 Linux 上的 nvm 安装方式基本一致,官方推荐用 curl 安装脚本:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash注意:这个命令会从 GitHub 拉脚本,如果网络不给力,可以走 gitee 镜像或者手动 git clone。手动 clone 的方式其实也很简单:
git clone https://github.com/nvm-sh/nvm.git ~/.nvm cd ~/.nvm git checkout v0.39.7 # 建议切到具体版本,而不是跟着主分支跑然后跑到你当前 shell 的配置里,把 nvm 初始化脚本加进去。以 zsh 为例,编辑~/.zshrc,加上下面三行:
export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # 加载 nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # 加载补全保存后source ~/.zshrc,然后执行:
nvm --version如果提示找不到命令,多半是你加到配置文件里的内容有问题,或者 shell 配置没重新加载。这是我见过最多人卡住的一步,十有八九是忘记 source 了。
注意:macOS 上如果之前用 Homebrew 装过 nvm,可以
brew uninstall nvm清掉再用脚本装,避免两个 nvm 打架。
3. 核心命令实战:安装、切换与默认版本配置
3.1 常用命令速查
先说结论:nvm 的核心命令其实就六七个,其他命令大多可以靠这几个组合出来。我整理了一张速查表,你可以先收藏,平时随用随查:
| 命令 | 作用 | 示例 |
|---|---|---|
nvm list installed | 列出本地已安装的 Node 版本 | 显示* 20.11.0表示当前版本 |
nvm list available | 列出可远程安装的版本 | Windows 下很有用,能看到全部版本号 |
nvm install <version> | 安装指定版本 | nvm install 18.19.0 |
nvm use <version> | 切换当前终端版本 | nvm use 20.11.0 |
nvm alias default <version> | 设置默认版本 | nvm alias default 20.11.0 |
nvm uninstall <version> | 卸载指定版本 | nvm uninstall 14.21.3 |
nvm current | 查看当前生效版本 | 比node -v更直观 |
macOS / Linux 版还有一些差异命令,比如nvm ls-remote对应 Windows 的nvm list available;mac/Linux 直接用nvm install node会装最新版,nvm install --lts会装最新的 LTS,Windows 版则需要给出版本号。
3.2 切换 Node 版本与全局配置 Node 的关键细节
我第一次在 Windows 上执行nvm use 18.19.0的时候,终端回显:
Now using node v18.19.0 (64-bit)然后我满怀期待地敲node -v,结果还是原来的版本。当时一下懵了,排查半天才发现是终端窗口没有重新打开,环境变量还是旧值。nvm use 只对当前终端进程和之后新开的终端生效,已经打开的老终端不会自动刷新 PATH。这个细节看起来基础,但后面几乎每隔一段时间就会遇到有人问。
正确的切换姿势是:
- 确认本地已经安装了目标版本:
nvm list installed - 执行切换:
nvm use 20.11.0 - 验证:
node -v和npm -v
Windows 下切版本后,可以顺手看下符号链接指向:
dir C:\dev\nodejs你会发现node.exe真的就在这个目录里,但它其实是 nvm 在切换时动态创建的目录(nodejs 目录本身被做成了 symbolic link)。
还有一个关键点是npm 是跟着 Node 版本走的。nvm install 20.11.0之后,npm 会自动随 Node 一起安装,所以你切到哪个 Node 版本,npm 命令就是那个版本自带的 npm,版本号可能都不一样。千万别试图单独“装一个 npm”,它不是这么工作的。
3.3 版本别名与默认版本设置技巧
如果说nvm use是手动挡,那nvm alias default就是让 nvm 变成自动挡。
很多新手装好 nvm,切到某个版本后,看着一切正常,结果重启电脑或新开一个终端,node -v又回到最初那个版本甚至直接找不到 node。原因很简单:nvm 不会记住你上次用哪个版本,除非你设置 default 别名。
设置默认版本:
nvm alias default 20.11.0Windows 版也可以直接:
nvm use 20.11.0然后执行nvm alias default 20.11.0,之后新终端窗口会自动切到 20.11.0。这个默认版本建议固定在稳定的 LTS 版本上,比如 18.19.0 或 20.11.0,不要追最新版。最新版通常刚发布一两个版本,生态里有些包还没跟上,容易踩兼容性坑。
macOS / Linux 版还有个进阶技巧:在项目根目录创建.nvmrc文件,里面写上一行版本号:
18.19.0然后敲nvm use(不带参数),nvm 会自动读取.nvmrc里的版本并切换。这样不同项目就算 Node 版本要求不一样,每次进目录执行一次nvm use就能切到正确版本,团队协作时也可以把.nvmrc提交到 Git,大家统一版本,配合 CI/CD 还能保持一致环境。
Windows 版 nvm-windows 对.nvmrc的支持比 mac/Linux 版弱,实测有些版本不认。如果你的 Windows 上执行nvm use报语法错误,就用完整版本号,别纠结。
4. 全局配置详解:npm 镜像、全局包管理与 pnpm
4.1 npm 镜像源配置与加速下载
在国内网络中,nvm 装 Node 时最痛苦的就是下载速度。默认的node_mirror走的是 Node 官方服务器,经常卡在 30% 不动,等半天直接失败。
有两个地方可以加速:
第一个是 nvm 下载 Node 二进制本身。Windows 版修改 nvm 安装目录下的settings.txt:
root: C:\dev\nvm path: C:\dev\nodejs node_mirror: https://npmmirror.com/mirrors/node/ npm_mirror: https://npmmirror.com/mirrors/npm/macOS / Linux 版在终端执行:
nvm node_mirror https://npmmirror.com/mirrors/node/设置完后重新执行nvm install,下载速度会有质的提升。
第二个是 npm 包仓库的 registry。安装完 Node 后,手动执行:
npm config set registry https://registry.npmmirror.com验证是否生效:
npm config get registry看到返回的是国内镜像地址就说明配置成功了。这里有一个细节:registry 只影响 npm 安装包时拉包的地址,不影响 nvm 下载 Node 二进制的地址。所以两个都要配,缺一个都会有一个环节特别慢。
4.2 全局包在多版本间的共享与管理
全局包是另一个高频问题:你在 Node 18 下npm install -g pnpm,切换 Node 20 后发现 pnpm 命令没了;或者切回 Node 18,pnpm 还在。这是因为nvm 隔离的不仅是 Node 版本,还包括每个版本对应的全局 node_modules 目录。
Windows 上,npm install -g安装的包放在当前 Node 符号链接目录的node_modules下。nvm 切版本时把符号链接指向另一个版本目录,旧版本的全局包自然就不在当前 PATH 里了。
这是设计如此,不是 bug。但很多人会用得不习惯。有两种解决思路:
第一种是把跨版本都要用的 CLI 工具在每个版本下都装一遍。比如我想在所有 Node 版本下都能用 pnpm,就在每个版本执行一次:
nvm use 18.19.0 npm install -g pnpm nvm use 20.11.0 npm install -g pnpm这样一劳永逸,但缺点是需要维护多份全局包,磁盘占用多。
第二种是用nvm reinstall-packages迁移全局包。这个命令在 mac/Linux 和较新的 nvm-windows 里都有,作用是把当前版本的全部全局包重新装到指定版本下:
nvm use 18.19.0 npm install -g some-cli nvm use 20.11.0 nvm reinstall-packages 18.19.0执行后,20.11.0 下会自动把 18.19.0 里所有的全局包装一遍。实测很方便,适合一次性迁移。
我的个人习惯是:全局包尽量精简,能用 npx 的就不全局装。像create-vite、create-next-app这种工具,用 npx 临时拉取就行,不需要全局安装,也省去了版本切换后找不到命令的烦恼。真正需要全局装的,也就是pnpm、yarn、nodemon、eslint这类每天都用的。
4.3 pnpm 的安装与配置
pnpm 是目前越来越多项目在用的包管理器,以“磁盘占用小、安装速度快、严格依赖隔离”著称。在 nvm 环境下装 pnpm 有两种方式。
方式一:全局安装
npm install -g pnpm装完后验证:
pnpm --version这里有个坑:如果你装了多个 Node 版本,只在一个版本下全局装了 pnpm,切到另一个版本后pnpm命令可能直接找不到。解决方案就是上面说的,每个版本都装一遍,或者用 Corepack。
方式二:Corepack 启用(推荐)
Node 16.13+ 自带 Corepack,不用额外装。开启 pnpm:
corepack enable corepack prepare pnpm@latest --activateCorepack 的好处是它会根据项目的packageManager字段自动切换 pnpm 版本,非常优雅。比如项目package.json里写了:
{ "packageManager": "pnpm@8.15.0" }Corepack 检测到后就会自动使用 8.15.0 这个版本,不用手动管。
pnpm 装好后,还需要设置两个路径,否则 store 会默认放到系统盘,全局 bin 也可能乱:
pnpm config set store-dir D:\.pnpm-store pnpm config set global-bin-dir C:\dev\pnpm-global-binmacOS / Linux 下路径写法换成自己的目录就行。设置完把global-bin-dir加进系统 PATH,这样pnpm install -g的全局命令才能在任意 Node 版本下访问。
5. 常见问题与排查技巧实录
5.1 “nvm 不是内部或外部命令”与环境变量问题
这是 nvm 相关最常见的问题,一般出现在刚装完 nvm-windows 后。原因基本就三个:
- 安装 nvm 后没有新开终端,旧终端缓存了旧环境变量。
- 安装时目录没选对,导致
NVM_HOME和NVM_SYMLINK指向了不存在的路径。 - 系统 Path 里没有
%NVM_HOME%。
排查方法很简单:新开一个终端,执行echo %NVM_HOME%,看看输出是否正常;再执行where nvm,如果找不到,就去环境变量里手动加上。macOS / Linux 版同理,提示command not found时,先检查~/.zshrc或~/.bashrc里的 nvm 初始化代码有没有写对,再确认当前 shell 有没有重新加载。
5.2 全局包路径错乱:claude.exe 相关报错场景
最近有不少人问我一个很典型的报错,长这样:
无法将“f:\nvm\nodejs/node_modules/@anthropic-ai/claude-code/bin/claude.exe”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。我一看就明白是怎么回事:你在某个 Node 版本下全局安装了@anthropic-ai/claude-code这个 CLI 工具,然后切到了别的 Node 版本,或者 nvm 符号链接出了问题。
当你执行npm install -g @anthropic-ai/claude-code时,npm 会在当前 Node 版本的全局 node_modules 下创建这个包的 bin 链接。在 Windows 上,nvm 的 nodejs 符号链接目录本身是动态的,切换版本会把目录指向另一个真实版本目录。如果切换前安装的 CLI 路径还残留在 PowerShell 的会话历史、npm全局缓存、或者某个项目的 node_modules/.bin 里,重新运行命令时就会去旧路径找 exe,找不到了自然报这个错。
遇到这种情况,按照下面的顺序排查:
- 确认当前 Node 版本是哪个:
nvm current。如果当前版本不是当初装 claude-code 的那个版本,全局包当然找不到。 - 切换回装过该包的那个版本,或者直接用
npm install -g @anthropic-ai/claude-code重装。 - 如果已经切回正确版本还是报错,八成是 nvm 符号链接本身坏了。在 Windows 下以管理员权限打开 PowerShell,执行:
nvm uninstall <当前版本> nvm install <当前版本> nvm use <当前版本>这会重建符号链接,把目录关系理顺。macOS / Linux 下不会这么容易坏符号链接,通常切回正确版本就恢复了。
还有一个容易被忽略的坑是PowerShell 执行策略。Windows 默认的 PowerShell 执行策略可能是 Restricted,导致所有通过 npm 全局安装的.ps1脚本都无法运行,报错内容和上面类似。顺手执行一下:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned这个设置只对当前用户生效,不影响系统安全,但能让 npm 全局命令的脚本正常跑起来。
5.3 nvm install 慢、卡住或下载失败的加速方案
除了镜像源配置,还有几个额外手段可以加速:
- Windows 下如果
settings.txt配置了node_mirror仍然慢,试试换个节点,比如清华、阿里、华为的 Node 镜像站,各家的稳定性在不同时间段略有差异。 - 安装特定版本时,如果 nvm 反复失败,可以先手动去镜像站下载对应的 zip 包,然后手动解压到 nvm 的安装目录下,再执行
nvm use识别。具体目录是nvm 安装目录\v版本号,比如C:\dev\nvm\v20.11.0。这种方式看起来绕,实际是应急时最快的路子。 - macOS/Linux 下可以设置
nvm_npm_mirror和nvm_node_mirror环境变量,效果和settings.txt一样,但可以做到 shell 全局配置里,不用每次刷。
这里要特别提醒:不要试图修改 node 目录结构来“优化” nvm。有人觉得C:\dev\nodejs里没有完整文件,就把真实版本目录里的文件手动 copy 进去,结果 nvm 切换版本的符号链接机制被破坏,后续各种报错。相信我,nvm 的目录结构是有意设计的,别动它。
5.4 切换后 node -v 没变化、版本显示不对
几种可能:
- 当前终端是旧的,PATH 没刷新。新开一个终端再试。
nvm use没有加--delete-prefix参数,而当前版本目录里残留了旧 npm 前缀配置。在 Windows 下如果报prefix相关的 error,执行:
nvm use --delete-prefix 20.11.0这个参数的原理是清除 npmrc 里旧版本的prefix配置,避免 npm 全局目录指向错误位置。
- 系统里同时存在多个 nvm。比如 macOS 上 Homebrew 装了一个,shell 脚本又装了一个,两个都在初始化时执行,互相覆盖。这种情况建议只保留一个,把另一个彻底卸载。
5.5 nvm 卸载后残留问题
最后说一句卸载。很多时候你卸载 nvm,会留下一堆“幽灵”文件——符号链接目录还指向某个不存在的版本、npm 缓存还在、nvm 目录没删干净。正确卸载 Windows 版 nvm 的方式是:
- 先执行
nvm uninstall卸载所有 Node 版本。 - 删除
NVM_SYMLINK指向的 nodejs 目录。 - 再卸载 nvm 程序本身,删掉 nvm 安装目录。
- 清理环境变量里和 nvm、nodejs 相关的条目。
macOS / Linux 下就简单了,删除~/.nvm目录和 shell 配置里的初始化代码即可。
最后说点我自己的体会
从第一次被 Node 版本折磨到装好 nvm,这个工具我已经用了好几年,最大的感受是:它不是帮你“管理版本”,而是帮你“消除环境焦虑”。以前最怕别人丢一个老项目过来说“帮我跑一下”,现在nvm use一敲就完事。还有个小习惯建议你从一开始就养成:所有新项目都写一个.nvmrc,哪怕你只有自己一个人维护,也写上。几个月后你回来看这个项目,就能省掉“当初用的哪个 Node 版本”这个灵魂拷问。nvm 的坑不少,但只要把安装路径、环境变量、符号链接这几个核心点理解透,剩下的基本都是熟练活。希望这篇教程能帮你少走点弯路。