Use nvm to Manage Multiple Versions of node.js

Have you ever been in a dilemma of upgrading your node.js version or not? I have multiple node.js projects I developed in the past using “latest” versions then, and I end up using node.js v8, v10, v12 and v14. One solution I used in the past is to use Docker, which works great. But managing those Docker images and making them up to date is not an easy task, especially when I don’t do this often and what ends up happening is lots of research with try and error when I have to do it.

Today I discovered nvm which solved my dilemma with a simpler workflow than using Docker. nvm allows me to install multiple versions
of node.js independently and switch between them easily. It’s very similar to the concept of virtualenv of python if you have used it
before. But nvm can’t create multiple environments like virtualenv does, because it doesn’t need to. In the
node.js world, your local package.json is the virtual environment and all nvm need to take care is the global packages and node.js
versions, which is exactly nvm provides and the reason it’s so simple to use.

According to the documentation, brew is not supported 😔. The recommended way to install is via curl or wget.

1
2
3
$curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
or
$wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

After this, you should see the additional configuration in your shell config file, in my case it’s .zshrc

1
2
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

Now nvm is ready to be used! Everything will be in NVM_DIR folder. nvm provides a very neat deep integration with zsh which allows automatic environment switch using a .nvmrc file in a given directory. In order for this to work, put the following snippet to .zshrc file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# place this after nvm initialization!
autoload -U add-zsh-hook
load-nvmrc() {
local node_version="$(nvm version)"
local nvmrc_path="$(nvm_find_nvmrc)"

if [ -n "$nvmrc_path" ]; then
local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")

if [ "$nvmrc_node_version" = "N/A" ]; then
nvm install
elif [ "$nvmrc_node_version" != "$node_version" ]; then
nvm use
fi
elif [ "$node_version" != "$(nvm version default)" ]; then
echo "Reverting to nvm default version"
nvm use default
fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc

Before installing node.js versions I’d like, I want nvm to install some default global npm packages I always use, so I create a .nvm/default-packages file and put the following npm packages

1
2
3
4
5
6
hexo
@ionic/cli
firebase-tools
@angular/cli
generator-ngx-rocket
apify-cli

Now let’s try to install two versions I use which are lts/dubnium(v10.20.1) and lts/erbium(v12.16.3).

1
2
$nvm install lts/dubnium
$nvm install lts/erbium

After this, you should be able to switch between different versions using version numbers or alias. Let’s try it out the automatic way. I have a project with a .nvmrc file and the content is lts/dubnium. My default nvm is configured to use lts/dubnium. Now let’s see it in action.

1
2
3
4
5
6
$cd timeGarden
Found 'timeGarden/.nvmrc' with version <lts/dubnium>
Now using node v10.20.1 (npm v6.14.4)
$cd ..
Reverting to nvm default version
Now using node v12.16.3 (npm v6.14.4)

It’s working like a charm! Don’t forget to commit the .nvmrc file so it will be a part of the project environment setup.

Reference:

nvm github page