Imagine you joined a Node.js project and want to bootstrap it to see how it goes, but you see an error. What is the problem? After spending some time, you find out that Node.js version you’re using on your machine is not the one that the project requires.
This is quite a common and annoying situation. I have been there myself. To avoid such troubles, smart people developed tooling called “node version manager.” A shell utility that allows you to switch between Node.js versions easily.
This article will focus on the Node.js version managers market. You’ll see how they differ and which one you should consider using.
Criteria
To make comparison easier, we’ll introduce the following criteria:
Cross-platform: Is the manager cross-platform?
Upfront setup: How much work must you do for the initial installation?
Node version sources: From what sources can the Node.js version be parsed?
Daily usage: How easy and seamless is using version manager daily?
Contestants
Comparison
With defined criteria, we can now look at each contestant in more detail.
Node Version Manager (NVM)
It is the most popular solution for node version management (at least by GitHub repository stars, 75.2k). The reason for that is its early appearance. It was one of the first, if not the first, Node.js version managers at the time and gained huge popularity in the community.
Is it cross-platform? Not really. It doesn’t have full Windows support. It works in some cases like GitBash (MSYS), Cygwin, and WSL (Windows Subsystem for Linux). There is a separate package for Windows called nvm-windows, but it is not NVM itself.
Another limitation is the support of POSIX shells only, such as bash or zsh, which leaves users of other shells, like Fish, out of the question.
The most straightforward way to install NVM is to run the following command.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
Here is how you use NVM to switch between different Node.js versions.
user@machine:~/project node -v
v21.7.2
user@machine:~/project cat .nvmrc
18.19.1
user@machine:~/project nvm use
user@machine:~/project node -v
v18.19.1
NVM can understand which version of Node.js to use through the .nvmrc
file. You must either create one before switching between versions or explicitly declare Node.js version to which you want to switch, e.g. nvm use 18.10
.
Notice that running the nvm use
command will set the Node.js version for the current shell. What does this mean? Even if you leave the project folder and navigate to another project, the Node.js version will stay the same until you rerun the nvm use command.
It adds more friction to your workflow and creates a greater cognitive load because you must always be aware of what Node.js version your current shell uses and what is required for a particular project.
It is still better than manually managing all possible Node.js versions, but far from seamless integration.
N
N is another popular Node.js version manager (18.5k GitHub starts).
It is not cross-platform and has even more limitations than NVM. It does not work in native shells on Microsoft Windows (like PowerShell), Git for Windows Bash, or with the Cygwin DLL.
N can be installed directly from NPM. Run npm install -g n
. It can also be installed with the Brew on macOS or by downloading the sh script.
curl -L https://bit.ly/n-install | bash
One of the big benefits of using N is its ability to detect Node versions directly from the “engines” section. If you have the following package.json structure:
{
"name": "project",
"version": "1.0.0",
"main": "index.js",
"engines": {
"node": "18.17.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"license": "ISC"
}
N will install “18.17.0” as you specified in the engines section.
However, N suffers from a similar problem to NVM. If you want to use the exact Node.js version for different projects, you have to keep track of it yourself.
Moreover, N takes this problem to a whole new level. Using N means managing a “global” Node.js version. Even after closing a shell, you’re left with the Node version you used for the latest project — not the best experience.
Fast Node Manager (FNM)
FNM is a node version manager written in Rust. It is as popular as N (15.2k GitHub stars).
FNM is the first cross-platform node version manager on the list. It runs on Windows without the need to install any other packages.
The installation process is clear and intuitive.
# macOS
brew install fnm
# Using rust package manager cargo
cargo - cargo install fnm
# On windows using winget
winget - winget install Schniz.fnm
Or using bash script for Unix-based OS.
curl -fsSL https://fnm.vercel.app/install | bash
FNM manages Node.js version per shell and doesn’t try to build its main workflow through global versioning like N does. It has a “default” version which is global and it plays the role of fallback in case some project doesn’t have a specified Node.js version.
The other cool feature of FNM is the auto-switching of Node.js version based on the folder you’re in, but you have to do some configuration for it.
Auto-switching works in the following way: If you go from one project that uses the 18.17.0 version to a different one with 20.12.1, FNM automatically switches Node.js version after you navigate into the new project folder.
user@machine:~ node -v
V21.7.2
user@machine:~ cd project-1
Using Node.js v18.17.0
user@machine:~/project-1 cat .node-version
18.17.0
user@machine:~/project-1 cd ..
user@machine:~ node -v
V18.17.0
user@machine:~ cd project-2
Using Node.js V20.12.1
user@machine:~/project-2 cat .node-version
v20.12.1
We switched between two projects, and the Node version automatically changed based on the .node-version file inside those projects.
You must install the required Node.js version on a machine to make auto-switching work properly.
The other thing to remember is that it can detect node versions only from extra files you create in a project. Those files are .node-version or .nvmrc.
Volta
Volta is a rising star in the world of version managers (10k starts on GitHub).
It is written in Rust, and it is cross-platform.
The installation process is seamless for Unix-based systems.
curl https://get.volta.sh | bash
Windows has a separate installer.
When you configure Volta's Node.js version, you do not need to create extra files. Volta uses configuration from package.json
.
{
"name": "project",
"version": "1.0.0",
"main": "index.js",
"engines": {
"node": "18.17.0"
},
}
The benefit of such a configuration is that the engines
section is right next to the Volta configuration. This allows you to keep them in sync effortlessly. When placed in a separate file, it is easy to forget to sync those versions.
Another huge feature is the management of a toolchain. What does it mean?
Imagine that you’re using Yarn as a package manager. Other Node.js version managers can manage only Node.js versions. At the same time, Yarn version can change from project to project.
That is where Volta shines. You can dynamically switch not only the Node.js version but Yarn version as well. Just add Yarn version under the “volta” configuration section.
"volta": {
"node": "18.17.0",
"yarn": "1.22.22"
}
Whenever you run the install command, Volta, ensure that Node.js and Yarn versions match the declared one. Isn’t it magical?
PNPM
Don’t be surprised. PNPM is usually perceived as an alternative to package managers like NPM and Yarn. However, unlike those, PNPM can manage Node.js version itself.
PNPM is cross-platform and provides the same Node.js version management experience throughout all platforms.
However, there are four downsides to using PNPM as a Node version manager.
The first one is that PNPM is not a Node version manager at its core. It is a package manager that can manage the Node.js version. You can’t easily use it with other package managers like NPM or Yarn.
The second one is that Node.js installed using PNPM is not shipped with Corepack. Here is the note from the documentation:
PNPM env does not include the binaries for Corepack. If you want to use Corepack to install other package managers, you need to install it separately (e.g. PNPM add -g corepack
).
The third one is that PNPM can only manage the Node.js version globally. You can’t configure it per-shell. If you try to install without the --global flag, you get the following error message:
"pnpm env use <version>" can only be used with the "--global" option currently
It doesn’t switch Node.js version dynamically as you navigate from project to project. This means you have to track it all yourself and ensure it matches the version required for a project.
Conclusion
The Node.js version managers have come a long way. NVM was the first and most popular solution for quite a long time and remains one.
But the ecosystem is evolving. Over time, different tools, such as N, FNM, and Volta, emerged. Each has pros and cons.
At this point, Volta seems to be our most feature-reach and complete Node.js version manager. It is cross-platform, provides a seamless experience in day-to-day usage, and takes care of other tools you use on the project.