DEV Community

Cover image for How to run multiple Node and Angular versions simultaneously
Patrícia Pereira
Patrícia Pereira

Posted on • Edited on

How to run multiple Node and Angular versions simultaneously

In my line of work as a Web Engineer, I have leaped through a decent amount of projects in a not so big amount of time. Not only that, but all of these projects had at least one Node based component and a big part of them also used Angular as their Frontend framework. So I eventually came to a point where I needed to actively work on my current project but be able to quickly switch back to any of the other projects.

I must admit that the first time this switch was needed, I naively downgraded both Node and Angular CLI… Only to then upgrade them again when I went back to working on my current project. Not only is this a time-wasting process, it is susceptible to errors from missing information. An Angular project's CLI version is in the package.json file, but what about the Node version? That is a piece of information that must be documented, and as we all know well, documentation is almost always left behind.

Each Angular version is compatible with a range of Node versions. When downgrading/upgrading Angular CLI, you also need to make sure the Node version being used is compatible. Besides, it's good practice to maintain versions during development, unless explicitly wanting to change them.

It was in that moment that I started to search for a possible solution to manage different Node and Angular versions for different projects. I found two concepts that seemed promising to be used together:

  • nvm, a version manager for Node
  • Local Angular CLI

nvm

nvm is a Node version manager command line tool. It allows the user to install multiple Node versions on its machine and then use different versions in separate shells simultaneously.

If you are not familiar with nvm commands, keep in mind that:

  • nvm run [arguments] is equivalent to node [arguments]
  • nvm exec [command] [arguments] is equivalent to [command] [arguments]

A normal nvm usage workflow (and the one we are going to use to manage different projects' Node versions) would be to install each project's Node version and then execute it in an independent project dedicated shell. Node can either be or not be natively installed in the machine, it does not make a difference for this use case.

For demonstration purposes, let's suppose we have the following projects:

  • Project XPTO, Node version 8.17.0
  • Project EPIC, Node version 12.16.1

To be able to execute both projects without needing to downgrade/upgrade your Node version, you have to:


1. Install both Node versions using nvm:
$ nvm install 8.17.0
$ nvm install 12.16.1
Enter fullscreen mode Exit fullscreen mode
2. Go to the directory of project XPTO and set nvm to use the correct Node version:
$ nvm use 8.17.0
# check Node version being used
$ nvm run -v # or just "node -v"
> Running node v8.17.0
> v8.17.0
# start project XPTO
$ nvm exec npm start # or just "npm start"
Enter fullscreen mode Exit fullscreen mode

By executing nvm use you are defining the Node version that nvm is going to run in that shell, not only in the directory where you executed the command.

3. Open a new shell, go to the directory of project EPIC and do the same for that project's Node version.

Now there are two different projects being executed by two different Node versions! What's missing? Well, nvm use action is shell session scoped, which means new shells will start with the default nvm version of Node. So when you come back to work tomorrow and open a shell to start either of your projects, nvm will no longer be pointing to their correct Node version.

Luckily, nvm has the .nvmrc file, which allows the user to specify a Node version to be used by nvm in a directory and all its sub-directories. Create this file in the root directory of your projects with the correct Node version:

# in project root directory
$ echo "8.17.0" > .nvmrc
Enter fullscreen mode Exit fullscreen mode

Make sure you always use nvm commands to execute Node or npm, given that these are the commands that search for and use the .nvmrc file:

# "node server.js" with Node version from .nvmrc
$ nvm run server.js
# "npm start" with Node version from .nvmrc
$ nvm exec npm start
Enter fullscreen mode Exit fullscreen mode

Now nvm will always run the correct Node version for your projects!

Local Angular CLI

If you are working on an Angular project, besides guaranteeing the correct Node version you also need to make sure you are using the correct Angular CLI version when running your ng commands.

When you create an Angular project, the Angular CLI is added as a development dependency to your project's package.json:

{
  ...
  "devDependencies": {
    "@angular/cli": "9.0.5",
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode

This means that independently of the Angular CLI version you have globally installed in your machine, there will be a locally-installed Angular CLI in node_modules folder after installing your projects' dependencies. What you need to do is make sure you execute this locally-installed version instead of the global one. You can do one of the following:


Use package.json scripts

The npm run-script command adds the node_modules/.bin binaries to the pre-existing shell's PATH that is then provided to the scripts. This means that scripts in package.json which execute ng will be running the locally-installed Angular CLI. If you also want to directly execute ng in the shell using this approach, you can add "ng": "ng" as a script in package.json.

{
  ...
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode
# serve your application with nvm and local Angular CLI
$ nvm exec npm start
# create an Angular component using local Angular CLI
$ nvm exec npm run ng g component my-cool-component
Enter fullscreen mode Exit fullscreen mode

Use node_modules/.bin/ng

Run the local Angular CLI by directly executing the binaries present in the node_modules/.bin folder in a shell.

# create an Angular component using local Angular CLI
$ nvm exec ./node_modules/.bin/ng g component my-cool-component
Enter fullscreen mode Exit fullscreen mode

Conclusion

By taking advantage of both nvm and local Angular CLI binaries, it is not only possible to manage different Node and Angular versioned projects, but also to do it in a simple and straightforward way.

With this methodology, it's important to never forget to use the nvm commands! It's true that a simple command (e.g. to start a project) turns a bit more verbose, but the trade-off of being able to work on and execute multiple projects seamlessly is a big plus.

Hope this is helpful for someone out there! 💡
And of course, thanks for reading. 🤓
If you have any question/suggestion/feedback, feel free to leave a comment. 📝

PatricePeartree @ Twitter

Top comments (22)

Collapse
 
andyghiuta profile image
Andy G

There's also nsv which I found to work better in Windows, especially for upgrading npm.

Collapse
 
patricepeartree profile image
Patrícia Pereira

I have heard of it, but I have never used it, I'll be sure to take a look at it someday.
What's the difference between them for that specific case of upgrading npm?

Collapse
 
andyghiuta profile image
Andy G

With nvm I had to use npm-windows-upgrade package, while with nvs you can simply do npm i -g npm. I also had trouble with the antivirus (McAfee) which had to be turned off while installing another version of node with nvm.

Thread Thread
 
patricepeartree profile image
Patrícia Pereira

Interesting to know... I've just used nvm on a Linux environment, never got to try nvm-windows, but now I'll keep that in mind.

Collapse
 
brightknight08 profile image
Tim Anthony Manuel

Thanks for the heads up!

Collapse
 
weasnerb profile image
Brian Weasner

Instead of creating scripts in every project of yours to run the local version of the angular cli, you can use the npx package! You can install it globally and then whenever you are inside a project with node modules you can run "npx the-tool-name" and it will run the tool local to the project. (In this instance if "the-tool-name" was ng, it would run the local version of the angular cli without the need to add ng as a script in the package.json)

Collapse
 
patricepeartree profile image
Patrícia Pereira

npx is really an useful tool, thanks for the tip!

Collapse
 
iranicus profile image
iranicus • Edited

Hey Patricia, just came across this article now and know the pain of operating across multiple angular version and node projects so this is very handy.

I set it up on my linux for my own personal projects and it seems after different node versions via nvm are installed and I run the "nvm run npm" start in the angular project directory I got a Cannot find module npm issue. I raised a ticket on the nvm github and yesterday I was told that after running "nvm use node version" its not necessary to run "nvm run npm start" due to the prior "nvm use" command being used.

Not sure if things have changed since you first uploaded this or not but wanted to pass that onto folks :>
If you are interested in the details of it the ticket can be found on: github.com/nvm-sh/nvm/issues/2284

Thanks now

Collapse
 
patricepeartree profile image
Patrícia Pereira

Hi. Yes, you're right, after nvm use you can execute only npm start and it will use the Node version you selected.

But actually the correct command to run npm as you were trying would be nvm exec npm start (not nvm run), maybe that's why you were getting an error? I see I have that command wrong in one of the sections of the post, I have a nvm run where a nvm exec should be (I'm going to edit that). Running the commands like this is only usefull if you have a .nvmrc file to avoid having to execute nvm use every time. But like you said, if you run nvm use, then you can actually just use the normal node and npm commands!

Collapse
 
patryktech profile image
Patryk

I just use docker. Define an image version as a variable, and you can easily manage all your infrastructure as code.

Collapse
 
patricepeartree profile image
Patrícia Pereira

Hi Patryk! Yeah, that was also my original approach (and the one I actually keep using the most). Do you use mounted volumes in your containers? I do, and sometimes the file system access to the host makes read/write operations slow, and that was what made me look for a different approach.

Collapse
 
patryktech profile image
Patryk

I use both bind mounts for development (in my Python and node containers), and named volumes in dev and production, e.g. for my databases.

I use Linux for development and production, and I've never noticed any performance issues.

Thread Thread
 
patricepeartree profile image
Patrícia Pereira

Same here, regarding the volumes. But when in Windows with a bind mount for development, a simple npm install would take a lot longer than when run in the host. Probably Windows related...

Collapse
 
clementmwendwa profile image
Clement Mwendwa

Why use nvm execute when you could just use npm? Considering you've switched the node versions already.

Collapse
 
patricepeartree profile image
Patrícia Pereira • Edited

By "switched the node versions already" do you mean executed nvm use [version]? Because if so, then when you open a new terminal, the version nvm will be using will no longer be the one you just defined. It will be the one to which the nvm default alias is pointing to.

The combination .nvmrc file + nvm exec/nvm run avoids having to run nvm use every time.

Collapse
 
clementmwendwa profile image
Clement Mwendwa

Got you, yeah meant after nvm use. For what it's worth though there's a tool to automatically switch versions when you have a .npmrc file
github.com/wbyoung/avn, you could have a script to do that as well.

Collapse
 
chachan profile image
Cherny

a bit offtopic but since this is about Angular versions, is there a way to know which versions of TypeScript are supported in the current Angular version?

Collapse
 
patricepeartree profile image
Patrícia Pereira

You can check the supported TypeScript versions for an Angular version in the @angular/compiler-cli/package.json:

{
  ...
  "peerDependencies": {
    ...
    "typescript": ">=3.6 <3.7"
  }
}

There seems to be a way to disable this version checking in case you want to install a version outside of that range. But I guess you should do that at your own risk.

Collapse
 
chachan profile image
Cherny

oh that's helpful. Thanks @patricepeartree

Collapse
 
nuni233 profile image
nuni233

How does nvm will affect the internal operations of Visual Code to create components, services etc. ?

Collapse
 
avimoraly profile image
Avi Moraly

what about when you want to create new angular project using
"ng new my_new_project"
what you gonna do when you still don't have local directory?

Collapse
 
patricepeartree profile image
Patrícia Pereira

Well, I guess you can have some workarounds for that. You can npm init a directory just to be able to install locally the Angular version you want, and then use that one to ng new your new project. Or you can leverage Docker with mounted volumes and create a project from within a container with your desired Angular version.