fnm 和 nvm 有什么区别?
fnm vs nvm
共同点:都用来管理多套 Node.js,都识别
.nvmrc/.node‑version,命令用法大体相似,可以做到几乎无缝迁移。
核心对比表
| 对比项 | nvm | fnm |
|---|---|---|
| 实现 | Bash Shell 脚本 | Rust 编译二进制单文件 |
| 启动速度 | 慢,每次开终端加载脚本,200‑400ms | 极快,毫秒级,几乎无延迟 |
| Windows | 原生不支持;要用独立项目 nvm‑windows,两套代码逻辑不一致 |
原生完整支持 Windows/macOS/Linux,一套工具全平台统一 |
| 自动切换 | 需要手动写 shell 钩子实现 cd 自动切版本 | 内置 --use‑on‑cd,开箱即用目录自动切换版本 |
| 安装方式 | git clone + shell 注入配置 | 单二进制,winget/homebrew/curl 一键安装 |
| 社区生态 | 老牌,教程、问题案例极多 | 较新,功能齐全,资料略少但够用 |
| 全局包 | 每个 Node 版本独立一套全局包,fnm 同样如此 | 每个 Node 版本独立一套全局包 |
| CI 使用 | 脚本安装,初始化慢 | 单二进制下载,CI 速度快 |
| 镜像配置 | 需要手动改下载源环境变量 | 支持 FNM_NODE_DIST_MIRROR 环境变量配置镜像地址 |
底层原理差异
- nvm:shell 脚本,每次打开终端修改
PATH环境变量来切换版本;新开终端会重新执行脚本,带来启动开销;shell 环境复杂时容易出现版本错乱问题。 - fnm:Rust 二进制,靠符号链接做版本切换,shell 只注入一小段环境逻辑;绝大部分逻辑在二进制程序内部执行,终端启动开销极小。
命令对照(迁移参考)
| nvm | fnm |
|---|---|
nvm ls |
fnm list / fnm ls |
nvm ls‑remote |
fnm list‑remote |
nvm install lts/* |
fnm install --lts |
nvm use 22 |
fnm use 22 |
nvm alias default 22 |
fnm default 22 |
nvm uninstall 22 |
fnm uninstall 22 |
fnm 额外好用:
fnm exec --using=20 -- node xxx.js,不改变当前 shell 环境,临时用指定版本跑一条命令,CI、脚本非常方便。
怎么选
✅ 选 fnm,如果:
- 你同时用 Windows + Mac/Linux,想要一套统一工具
- 受不了打开终端卡顿、shell 启动慢
- 想要 cd 进项目自动切换版本,不想写复杂钩子
- CI/自动化脚本场景,追求快速安装
✅ 选 nvm,如果:
- 只使用 macOS / Linux,习惯老生态,大量旧项目文档都是 nvm
- 遇到疑难问题,优先搜网上海量 nvm 排错案例
迁移注意
不要同时加载两者的 shell 配置,会互相干扰 PATH。
如果你从 nvm 迁移 fnm:注释掉 nvm 的 shell 加载代码,再配置 fnm 的 eval "$(fnm env --use-on-cd)"。
fnm 支持导入 nvm 已经下载好的 node:fnm install --from‑nvm。
小坑:fnm 不会复用 nvm 的全局 npm 包,每个 node 版本包完全隔离,和 nvm 行为一致。