Node 版本管理:Windows 用 fnm,macOS 用 nvm
多项目、多机器协作时,Node 版本不一致很容易踩坑。最终方案很简单:
| 系统 | 工具 | 说明 |
|---|---|---|
| Windows | fnm | 原生支持 Windows,速度快,读 .nvmrc |
| macOS | nvm | 生态成熟,同样读 .nvmrc |
项目默认版本统一用根目录的 .nvmrc 锁定,两边都能识别。
早期用过 n,Windows 上也试过 nvm-windows;现在跨平台协作更推荐上面这一套:文件格式统一、命令习惯接近、和 CI(node-version-file: .nvmrc)也好对齐。
为什么 Windows 不推荐 nvm?
这里说的「nvm」在 Windows 上通常指 nvm-windows,它和 macOS/Linux 上的 nvm-sh/nvm 不是同一个东西。
核心差异在于:切版本时影响的范围。
nvm-windows:改的是全局 Node
nvm-windows 会在系统 PATH 里放一个全局唯一的符号链接(例如指向 C:\Program Files\nodejs)。执行 nvm use 18 时,它改的是这个全局链接的目标目录。
结果是:
- 一切开着的终端、IDE、脚本立刻都变成新版本
- 项目 A 切到 18、项目 B 需要 22 时,两边会互相踩
- 切换往往还要管理员权限(创建/修改系统级 symlink)
也就是说,它更像「整机换一套 Node」,而不是「当前这个项目/这个终端用哪套」。
fnm:按终端用软链接隔离
fnm 同样用软链接,但是每个 shell 会话各自一份(multishell):打开终端时,把当前会话的 PATH 指到一个临时软链接,再由这个链接指向具体的 Node 安装目录。
因此:
fnm use/ 进目录自动切换,只影响当前终端- 可以一边开着 Node 18 的窗口,一边开着 Node 22 的窗口
- 配合
--use-on-cd读.nvmrc,按项目切版本,不会把整机全局版本拧来拧去
| nvm-windows | fnm | |
|---|---|---|
| 机制 | 系统 PATH 上的全局 symlink | 每个 shell 一份 multishell 软链接 |
use 影响范围 | 整机、所有窗口一起变 | 仅当前终端 |
| 多项目并行 | 容易互相覆盖 | 互不影响 |
与 .nvmrc | 支持弱、习惯偏手动全局切 | 原生友好,可进目录自动切 |
所以 Windows 上最终选 fnm:同样是软链接思路,但作用域是「会话 / 项目」,而不是「改全局 Node」。
macOS 继续用 nvm 没问题——那边的 nvm 是改当前 shell 的环境变量,本身就是会话级的,和 Windows 上 nvm-windows 的全局行为不是一回事。
一、用 .nvmrc 锁定项目版本
在项目根目录创建:
echo "22.12.0" > .nvmrc内容只写版本号即可,例如:
22.12.0建议同时在 package.json 里声明:
{
"engines": {
"node": "22.12.0"
}
}GitHub Actions 可直接读 .nvmrc,避免文档、本地、CI 各写一份版本号:
- uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"二、Windows:fnm
安装
# winget(推荐)
winget install Schniz.fnm
# 或 scoop
scoop install fnm配置 PowerShell
安装后需要把 fnm 接到当前 shell。编辑配置文件:
notepad $PROFILE若提示文件不存在,先创建:
if (!(Test-Path -Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force }
notepad $PROFILE写入:
fnm env --use-on-cd --shell powershell | Out-String | Invoke-Expression保存后重新打开终端。--use-on-cd 表示 cd 进带 .nvmrc 的目录时自动切版本。
常用命令
fnm install # 按当前目录 .nvmrc 安装
fnm install 22.12.0 # 安装指定版本
fnm use # 切换到 .nvmrc 版本
fnm use 22.12.0 # 切换到指定版本
fnm default 22.12.0 # 设置全局默认
fnm list # 已安装版本
fnm uninstall 18.20.4
node -v # 确认当前版本进项目后的最短路径:
fnm install
fnm use
node -v三、macOS:nvm
安装
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash按脚本提示写入 ~/.zshrc(或 ~/.bashrc),重新打开终端。也可手动确认有类似内容:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"常用命令
nvm install # 按当前目录 .nvmrc 安装
nvm install 22.12.0 # 安装指定版本
nvm use # 切换到 .nvmrc 版本
nvm use 22.12.0 # 切换到指定版本
nvm alias default 22.12.0
nvm ls
nvm ls-remote
nvm uninstall 18.20.4
node -v进项目后的最短路径:
nvm install
nvm use
node -v需要 cd 自动切换时,可参考 nvm Deeper Shell Integration。
四、日常协作流程
- 仓库根目录提交
.nvmrc(版本号与团队约定一致)。 - Windows:
fnm install && fnm use;macOS:nvm install && nvm use。 node -v与.nvmrc一致后再npm install/ 跑脚本。- 升级项目 Node 时:改
.nvmrc(以及engines.node)→ 本地重新install+use→ CI 自动吃到新版本。
| 场景 | 建议 |
|---|---|
| 团队协作 | 只认 .nvmrc,不要口头约定版本 |
| 构建结果不一致 | 先看 node -v 是否和 .nvmrc 一致 |
| 多项目频繁切换 | Windows 开 fnm 的 --use-on-cd;macOS 配 nvm 的目录集成 |
五、参考链接
旧方案备忘
若机器上还装着 n 或 nvm-windows,可以逐步迁到 fnm / nvm。旧命令大意如下,仅作对照,新项目不必再跟:
# 曾经的 n(偏 macOS / Linux)
sudo npm install -g n
sudo n 22.12.0
n # 交互选择已安装版本