Sensidev logo
Hero Image

Using nvm to deal with different versions of Node.js - Apple Silicon support included

by Ionuț Movilăalmost 3 years ago 4 min read

Motivation

As developers, we are often faced with the challenge of running different projects that have particular requirements regarding a specific version of node to be used.

I came across this issue while trying to run our website project built with React and Gatsby, started in the summer of 2020. It was not a very old project and on my M1 mac I already had installed node v16 which is the LTS version starting from Oct. 2021 and has native support for Apple silicon chips . But getting our project to run with v16 showcased many of problems, and after spending 2-3 hours trying to upgrade libraries with installation errors, I gave up and shifted my focus into making the project run with the previous node LTS v14, while also being able to run the more recent projects with newer versions of node like v16 or even v17.

Before starting

The very popular tool that deals with different versions of node is called Node Version Manager (or nvm).

Before installing nvm we should remove all existing versions of node and also yarn if you use it. Because I had them installed via Homebrew , it was as simple as running the following commands:

brew remove yarn
brew remove node@14
brew remove node@16

Installing nvm

The easiest way to install nvm is to use curl or wget commands found here .

Installing different versions of node with nvm

With nvm installed we can pull any version of node we want with a simple command like: nvm install 14, or for installing the current LTS version: nvm install --lts.

After installing multiple versions of node we can set a default version using the alias command, like: nvm alias default 16.

Running on Apple Silicon (M1, M1 Pro and M1 Max)

If you want to use node versions older than v16 that are not natively supported by arm64 architecture (this is the architecture used by Apple Silicon chips) the best option is to install these versions from pre-build binaries that are available but only for the more traditional i386 architecture.

The trick here is to switch your terminal to i386 architecture, and if you're using the default Zsh shell this can be done using the command arch -x86_64 zsh and then you can confirm the new architecture was activated by running arch command that should output i386. The versions of node installed this way will run in emulated mode using Rosetta translator.

After this you can safely install any node version older than v16 using nvm. But remember to switch back to native architecture before installing versions >=v16, by using the command arch -arm64 zsh (or just close the terminal window and open a new one).

Installing yarn with node

Now that we have node installed, yarn installation will be related to the current active version of node. The installation of yarn goes as regular by using npm: npm install --global yarn

If you forget to install yarn for the active version of node when trying to run it, you will be greeted with an error message that yarn is not installed.

Enforcing a specific node version for a project

To make things easier and error-prone, JavaScript projects should specify in the package.json file the supported versions of node. For this we should use engines configuration, that can be like this:

 "engines": {
    "node": "14"
  },

It will only allow npm (or yarn) commands to be executed if the proper node version is installed and activated, otherwise an error message will be displayed. In this case we are only allowing project commands if using node v14.

Activating the project specific node version is as easy as running nvm use in the folder with package.json file. Then we can confirm the version was activated with node --version.

If the project does not specify a version for the node engine you can activate a certain version of node by using a command like this one: nvm use 16.

Conclusions

Not until long ago I was using a single version of node and most of the projects were running without issues. But once you have old and new projects that you need to run on the same machine nvm will be your friend. And the reason is simple: for old projects that need very small maintenance work — upgrading to a newer version of node can be time-consuming and requires upgrading other project libraries and all these cascading changes can introduce regression bugs, so you get the point why upgrading is not the optimal solution.

Please leave your comments regarding any issues you had related to using different versions of node, and what was the solution you or your team came with.

Dev Thoughts