A better Node version manager: Volta vs nvm

Is Volta as fast and snappy as it claims to be?

Duncan Lew
8 min readNov 29, 2022

The Node.js ecosystem has been undergoing developments to its JavaScript tools, which makes the JavaScript tooling that we use more robust, reliable, and fast. One specific tool that we’re going to take a look at is the version manager for Node.js. When you’re frequently switching between different Node.js repositories, managing the specific versions of Node should be a very mundane process. The established management tool recommended by many for Node is nvm. Just because nvm has been around for a long time and is used by many developers does not necessarily mean that it’s the best tool for the job. There are other toolchains like Volta that claim to do a better job than nvm. Today, we’re going to take a look at whether these claims hold water and how to immediately get started with Volta on your machine.

1. The new kid in town: Volta

Volta logo

Volta is a JavaScript tool built on Rust for managing different Node.js versions. This tool can run on Windows, macOS, and Linux systems, making it a truly universal version manager for Node.js with cross-platform support. Volta claims to be very fast and seamless in its startup time and per-project version switching. Is Volta faster and snappier than the established nvm for managing your Node.js versions? We’re going to put these claims to the test.

Getting started with Volta

Volta is very easy to install on your system. If you have a macOS or a Linux machine, you can install Volta with the following command:

curl https://get.volta.sh | bash

The successful output for installing Volta will look like this:

Installation result of Volta

This script will install Volta and update your bash, zsh, or fish startup script immediately.
If you have a Windows machine, you can download and run the installer from the following link.

After the installation you can install Node.js version 18 like this:

volta install node@18

It sounds counterintuitive, but switching to a different Node.js version with Volta is also done by using the install command.

volta install node@16

The last volta install command that is run, makes that Node.js version the default one.

2. Benchmarking approach 📏

In order to test Volta’s speed claims, we’re going to use two MacBooks with the following CPU configurations:

  • 16-inch 2019, 2.6 GHz 6-Core Intel Core i7
  • 16-inch 2021, Apple M1 Pro

For brevity in the rest of the article, we’re going to call these machines an Intel machine and an M1 machine. On both the Intel and M1 machine, we’re using zsh as the default shell and have nvm installed. For benchmarking, we’re going to use the zsh profiler and measure the time needed for a zsh startup to interactivity.

Zsh profiler

We’ll profile the startup times of our Terminal with nvm in the startup script and see how this differs when we install Volta. This way we can see if Volta delivers on its speed promises compared to nvm.

Profiling the startup time in zsh can be done with the built-in profiler called zprof. This can be done very easily by placing zmodload zsh/zprof at the beginning of your ~/.zshrc file and zprof at the bottom. We can use the profiling results to analyze which processes are being run and how time-consuming they are during the zsh startup.

Startup time measurement

Measuring the startup time before zsh becomes interactive can be done by running the following command:

time  zsh -i -c echo

3. Putting Volta’s speed claims to the test with benchmarks 🏎️

Now it’s time to get down to the nitty-gritty of actually running the measurements! When we run the zsh profiler for the Intel machine, we get the following results:

num  calls                time                       self            name
-----------------------------------------------------------------------------------
1) 1 446.15 446.15 90.42% 169.93 169.93 34.44% nvm_auto
2) 2 276.22 138.11 55.98% 151.08 75.54 30.62% nvm
3) 1 102.95 102.95 20.86% 86.29 86.29 17.49% nvm_ensure_version_installed
4) 1 21.97 21.97 4.45% 16.77 16.77 3.40% nvm_die_on_prefix
5) 1 16.66 16.66 3.38% 16.66 16.66 3.38% nvm_is_version_installed
6) 2 15.11 7.56 3.06% 15.11 7.56 3.06% compaudit
7) 1 22.02 22.02 4.46% 6.91 6.91 1.40% compinit
8) 1 6.32 6.32 1.28% 6.32 6.32 1.28% (anon)
9) 1 4.88 4.88 0.99% 4.88 4.88 0.99% nvm_grep
10) 1 4.68 4.68 0.95% 4.68 4.68 0.95% zrecompile
11) 1 4.44 4.44 0.90% 4.44 4.44 0.90% __sdkman_export_candidate_home
12) 1 3.97 3.97 0.80% 3.97 3.97 0.80% __sdkman_prepend_candidate_to_path
13) 1 1.32 1.32 0.27% 1.32 1.32 0.27% regexp-replace
14) 14 1.10 0.08 0.22% 1.10 0.08 0.22% compdef
15) 5 0.92 0.18 0.19% 0.92 0.18 0.19% is-at-least
16) 1 0.84 0.84 0.17% 0.84 0.84 0.17% colors
17) 4 0.54 0.14 0.11% 0.54 0.14 0.11% add-zsh-hook
18) 2 0.48 0.24 0.10% 0.48 0.24 0.10% bashcompinit
19) 4 5.21 1.30 1.05% 0.33 0.08 0.07% nvm_npmrc_bad_news_bears
20) 1 0.21 0.21 0.04% 0.21 0.21 0.04% nvm_has
21) 6 0.15 0.03 0.03% 0.15 0.03 0.03% is_plugin
22) 4 0.11 0.03 0.02% 0.11 0.03 0.02% pathadd
23) 1 0.08 0.08 0.02% 0.08 0.08 0.02% _install-omp-hooks
24) 1 0.15 0.15 0.03% 0.07 0.07 0.02% complete
25) 3 0.07 0.02 0.01% 0.07 0.02 0.01% is_theme
26) 2 0.04 0.02 0.01% 0.04 0.02 0.01% env_default
27) 1 0.03 0.03 0.01% 0.03 0.03 0.01% fig_reset_hooks
28) 1 446.18 446.18 90.42% 0.03 0.03 0.01% nvm_process_parameters
29) 1 0.03 0.03 0.01% 0.03 0.03 0.01% detect-clipboard
30) 2 0.02 0.01 0.00% 0.02 0.01 0.00% __sdkman_echo_debug
31) 1 0.01 0.01 0.00% 0.01 0.01 0.00% nvm_is_zsh

-----------------------------------------------------------------------------------

From this profiling table, we can see that more than 90% of the startup time is occupied by nvm. This is a very shocking revelation.

Running the same profiler for the M1 machine produces a similar result. We can also see that in the case of the M1 Mac more than 90% of the startup time is consumed by nvm processes.

num  calls                time                       self            name
-----------------------------------------------------------------------------------
1) 2 211.82 105.91 74.12% 115.62 57.81 40.46% nvm
2) 1 79.78 79.78 27.92% 68.59 68.59 24.00% nvm_ensure_version_installed
3) 1 256.20 256.20 89.65% 44.38 44.38 15.53% nvm_auto
4) 2 14.99 7.49 5.24% 14.99 7.49 5.24% compaudit
5) 1 14.95 14.95 5.23% 14.86 14.86 5.20% nvm_die_on_prefix
6) 1 11.20 11.20 3.92% 11.20 11.20 3.92% nvm_is_version_installed
7) 1 4.30 4.30 1.51% 4.30 4.30 1.51% zrecompile
8) 1 4.15 4.15 1.45% 4.15 4.15 1.45% (anon)
9) 1 18.29 18.29 6.40% 3.30 3.30 1.15% compinit
10) 1 1.47 1.47 0.51% 1.47 1.47 0.51% nvm_has
11) 1 0.77 0.77 0.27% 0.77 0.77 0.27% regexp-replace
12) 1 0.49 0.49 0.17% 0.49 0.49 0.17% colors
13) 5 0.48 0.10 0.17% 0.48 0.10 0.17% is-at-least
14) 13 0.46 0.04 0.16% 0.46 0.04 0.16% compdef
15) 4 0.29 0.07 0.10% 0.29 0.07 0.10% add-zsh-hook
16) 6 0.09 0.02 0.03% 0.09 0.02 0.03% is_plugin
17) 4 0.09 0.02 0.03% 0.09 0.02 0.03% nvm_npmrc_bad_news_bears
18) 4 0.07 0.02 0.02% 0.07 0.02 0.02% pathadd
19) 1 0.08 0.08 0.03% 0.04 0.04 0.01% complete
20) 1 0.04 0.04 0.01% 0.04 0.04 0.01% _install-omp-hooks
21) 3 0.03 0.01 0.01% 0.03 0.01 0.01% is_theme
22) 1 0.03 0.03 0.01% 0.03 0.03 0.01% fig_reset_hooks
23) 2 0.02 0.01 0.01% 0.02 0.01 0.01% bashcompinit
24) 1 256.21 256.21 89.65% 0.01 0.01 0.00% nvm_process_parameters
25) 2 0.01 0.01 0.00% 0.01 0.01 0.00% env_default
26) 1 0.01 0.01 0.00% 0.01 0.01 0.00% detect-clipboard
27) 1 0.00 0.00 0.00% 0.00 0.00 0.00% nvm_is_zsh

Measuring startup time to interactivity between nvm and Volta

Now that we’ve profiled the startup of zsh until it becomes interactive, it’s time to measure the actual startup time of zsh itself.

time zsh -i -c echo

This command will output 3 parameters: the user, system, and total startup time. This is an example of the output command in which I’ve replaced the actual numbers with ***.

*** user *** system 75% cpu *** total

All these numbers are expressed in seconds. The parameter that we are going to focus on for the startup time is the last one which is the total startup time.

On our Intel machine, we are going to measure the zsh startup time twice. Once with nvm turned on and the other time with Volta enabled. This is the result:

# Intel zsh startup time
0.72s user 0.60s system 75% cpu 1.744 total # with nvm
0.15s user 0.16s system 97% cpu 0.314 total # with Volta

These are some shocking numbers! The total startup time with nvm is 1.744 seconds. When we enabled Volta as our Node version manager, the startup time dropped to 0.314 seconds. Volta is faster by 1.43 seconds. This is a whopping reduction of 82%! Imagine all the seconds you save waiting for your Terminal to startup zsh. 💨

The next step is to also measure the startup time for our M1 machine. M1 is no slouch to begin with. We wonder whether using Volta would even be worth it on an M1 machine that already has one of the industry’s best-optimized silicon chips based on the ARM architecture. These are the M1 results:

# M1 zsh startup time
0.14s user 0.21s system 70% cpu 0.496 total # with nvm
0.06s user 0.07s system 74% cpu 0.174 total # with Volta

M1’s startup time with nvm is only 0.496 seconds. This is already more than a second faster than the Intel machine with nvm, which has a startup time of 1.744 seconds. However, if we enable Volta on M1 the startup time can be reduced even more to 0.174 seconds. We can shave off 0.322 seconds of startup time with Volta. This computes to a startup time reduced by 65%! M1 had no trouble starting up quickly with nvm, but it can become even faster with Volta! ⚡️

Takeaway

The JavaScript ecosystem is developing at an even faster pace than before. Keeping up with all these new technological developments in the JavaScript scene can be daunting. New tooling that gets developed like Volta certainly dares to challenge the established norm like nvm. We were able to achieve a reduction in the startup time of 82% and 60% for an Intel and Mac machine, respectively. The biggest contributing factor to Volta being so snappy seems to be its foundation which is built on Rust. We might see even more tooling in the future being built with Rust or Go which makes good use of parallelism and memory optimizations. I hope that this article can shed some light on one of the new tools in the JavaScript environment. Happing coding! 😎

If the content was helpful, feel free to support me here:

--

--

No responses yet