Can Mise replace Volta?

Mostly yes—if you don't have projects that rely on outdated npm versions or need Windows support

Written by Rico Sta. Cruz
(@rstacruz) · 20 Feb 2024
...

Mise is new, just as Volta once was. But is it time to switch from Volta to Mise? I tried to answer this question by comparing the two.

What is Volta?

  • Volta replaced early Node.js version switcher tools (nvm, fnm, etc)
  • Volta has better integration with Node.js ecosystem, including npm and Yarn
  • Volta v1 was released Dec 2020

Volta, in my humble opinion, marked a new generation of Node.js version switcher tools.

There were a lot of tools before Volta. Almost all of them did the same simple thing: swapping out the node binary depending on what version a project needs.

Volta had deeper integration into the Node.js ecosystem than these tools. It supported managing npm and Yarn. It allowed managing global npm packages. It migrated global npm packages whenever new Node.js packages were installed.

Volta wasn’t a generic tool that swapped out node binaries, it was purpose-built to manage the Node.js ecosystem of tools.

What is Mise?

  • Mise manages Node.js, pnpm, Bun, Ruby, Python, and everything else
  • Also manages Ruby, Python, and just about anything really
  • First released as “rtx” in Jan 2023

Mise also changed the landscape of version managers, but in a different way than Volta.

There are version managers for Ruby, Python, Node.js, and more (rvm, virtualenv, nvm), and more. They all did the same thing: swap out the ruby or python binary depending on what version a project needs, and manage some environment variables.

Wouldn’t it be great to make one version manager to do all of that for any tool? That version manager does exist. asdf was a toolchain manager with a large plugin ecosystem, and supported all of those and more.

Mise rewrote asdf in Rust while maintaining compatibility with asdf plugins. It wasn’t just a rewrite, though: it was an extension of its legacy. It sought to fix asdf’s UX issues, improve its performance, manage environment variables, add a task runner, and more.

With Mise’s incredible amount of features, and promises of speed, it’s hard to ignore.

Comparison

Here’s a summary of things I’ve compared. (I’ve also added nvm here as a reference to the previous generation of tools that Mise and Volta took inspiration from.)

MiseVoltanvm
Managing runtimes:
Node.js
Bun and Deno
Managing package managers:
Corepack
pnpm 1 2 1
Yarn 1 1
npm
Specifying versions:
Pinning exact versions (node@20.10.1)
Pinning version ranges (node@20)
Per-project config files:
Committed to repo
.node-version compatibility
Not committed to repo
Speed:
Overhead in binaries0ms~1ms?
Shell startup time~4ms0ms?
Features:.
Windows support
Upgrade tools ?

Bun and Deno

  • Mise: supports Bun, Deno, Ruby, Python and more
  • Volta: only Node.js (and yarn, npm)

Mise supports Bun and Deno out-of-the-box, unlike Volta.

In fact, Mise primary appeal is supporting other tools too, like Ruby, Python and a lot more. Personally, I also use it for managing other tools that aren’t runtimes, such as Neovim and shellcheck.

Volta has had open issues for adding Deno support since May 2020, and Bun support since Mar 2023.

Terminal window
mise use --global bun@latest
mise ~/.config/mise/config.toml tools: bun@1.0.27
mise use --global deno@latest
mise ~/.config/mise/config.toml tools: deno@1.40.5

Corepack

  • Mise: Node.js’s builtin Corepack can manage pnpm and Yarn.
  • Volta: Has issues working with Corepack. Instead, Yarn is managed by Volta, but pnpm support is experimental.

Node.js ships with its own toolchain management utility called Corepack. Corepack can install pnpm and Yarn, and pin its versions per-project.

Corepack is the primary way I prefer Mise to manage alternate package managers like Yarn and pnpm. While Volta comes with its own built-in support for Yarn, Mise doesn’t need it—Corepack can do it.

Volta currently has issues working with Corepack.

PS: Mise has an optional config option to enable Corepack automatically, removing the need to run corepack enable when new Node.js versions are installed.

pnpm

Example: pnpm via Corepack on Mise
corepack enable
corepack use pnpm@8
Installing pnpm@8.15.3 in the project...
Done in 356ms
cat package.json
{
.
.
"packageManager": "pnpm@8.15.3"
}
pnpm -v
8.15.3

What about Mise’s pnpm plugin?

Mise has a pnpm plugin, but Corepack may offer a better experience.

Yarn

  • Mise: Yarn is available in Mise via Corepack. There are other ways to get Yarn installed and managed per-project on Mise, but I haven’t found them to be worth using.

  • Volta: has built-in support for Yarn.

Example: managing Yarn via Corepack on Mise
corepack enable
corepack use yarn@1
Installing yarn@1.22.21 in the project...
.
.
success Saved lockfile.
Done in 0.04s.
# `corepack use` will update package.json
cat package.json
{
.
.
"packageManager": "yarn@1.22.21+sha256...."
}
yarn -v
1.22.21

What about Mise’s Yarn plugin?

Mise’s asdf-yarn plugin has issues installing some versions of Yarn. I’d consider using Corepack instead.

What about Yarn’s built-in version management?

Yarn’s yarn set version <version> tool comes with a dealbreaker caveat for Yarn v1 for me. I’d consider using Corepack instead.

npm

  • Mise: Only the latest npm is what I’d consider reliably supported
  • Volta: has built-in support for npm

Corepack has opt-in support for npm, but I’ve found that this doesn’t work with Mise. Also, Mise (or asdf) has no plugin for npm right now. With Mise, the best option is to use the latest npm version.

This isn’t to say npm won’t work with Mise, it’s just that older projects can’t pin to older versions of npm if needed and offer a seamless experience. With that said, there are workarounds available:

  • Using corepack npm instead of npm (eg, corepack npm install), or
  • Using npm via npx (npx npm@7 --version)

On the other hand, Volta has built-in support for npm with no notable issues.

Specifying versions

  • Mise: Projects can use version ranges
  • Volta: Volta always resolves to a specific version

Mise allows specifying versions as ranges. For example, mise use node@20 will use any 20.x version. This is particularly great for specifying global versions, such as with mise use --global bun@latest.

In contrast, Volta will always resolve a version range to a specific version. For example, volta pin node@20 will pin 20.10.4.

Idiomatic files (.node_version)

  • Mise: can share Node.js version config with other tools (.node-version)
  • Volta: uses its own custom package.json field

Mise can store Node version config in .node-version a format compatible with other tools. It’s interoperable with GitHub Actions, Netlify, Cloudflare Pages and more (1, 2).

On the other hand, Volta uses a custom package.json field that’s only used by Volta. Users of Volta are forced to commit this configuration to the repository.

Configuring tool versions

  • Mise can store Node.js version config in formats that work with other tools
  • Mise can also override versions locally
  • Volta can only store Node.js versions in the “volta” field of package.json, no overrides

With Volta, the Node.js version is committed to the repository in a custom package.json field. This is considered a feature, because it means reproducible environments for everyone—at least, for everyone using Volta.

With Mise, there are many options for setting Node.js versions:

  • .node-version — works with other tools
  • .mise.toml — the default
  • .mise.local.toml — local overrides designed not to be committed to the repo
  • .tool-versions — legacy compatibility with asdf

Using a local config .mise.local.toml is great for testing version upgrades.

Upgrade tools

  • Mise: mise upgrade upgrades everything and cleans out old versions
  • Volta: volta install node@latest will install new versions, but not clean out old ones

Mise offers a great way to manage getting the latest version of a tool. For example, mise use --global bun@latest will pin the latest Bun version as the global executable.

After a few weeks, running mise upgrade will install new versions of Bun, and clean out old ones. In contrast, Volta has volta install node@20, but it won’t clean out older versions.

Upgrading with mise
mise use --global node@20
mise ~/.config/mise/config.toml tools: node@20.10.4
node -v
20.10.4
# 1 month passes...
mise upgrade
mise bun@1.0.29 downloading bun-linux-x64-baseline.zip ...
mise node@20.11.1 downloading node-x86_64-linux-gnu.zip ...
.
.
mise bun@1.0.29 installed
mise node@20.11.1 installed
mise bun@1.0.27 removing ~/.cache/mise/bun/1.0.27
mise node@20.10.4 removing ~/.cache/mise/node/20.10.4
node -v
20.11.1

Speed overhead in binaries

  • Mise doesn’t use shims
  • Volta adds around 1ms of startup time per node invocation through shims

Volta, like other version management tools, create a small node executable that will pass control to the real node binary. This is called a “shim”.

Shims add a little bit of overhead to the startup time of the real binary. Volta’s Rust-made compiled shims are quite fast, averaging at a negligible 1ms on my machine.

Mise doesn’t rely on shims for its functionality.

In contrast, shell-based tools (nvm) are much slower than both Mise and Volta.

Shell startup time

  • Mise: runs a mise activate command on shell startup
  • Volta: only sets PATH on shell startup

Volta doesn’t add any startup time the shell. All it does is add its bin directory to the path.

In contrast, Mise has a script that runs on shell startup and on every directory change. This script takes around 4ms to run in my machine. This 4ms penalty also applies to changing directories.

~/.config/fish/config.fish (Volta)
# Volta's recommended fish config: sets environment vars
set -gx VOLTA_HOME "$HOME/.volta"
set -gx PATH "$VOLTA_HOME/bin"
~/.config/fish/config.fish (Mise)
# Mise's recommended fish config: executes a script
"$HOME/.local/bin/mise" activate fish | source
# time mise activate fish
# => Executed in 4.97 millis

My closing thoughts

So is Mise better than Volta? Or is Volta still the preferred Node.js version manager? I think it’s not a straight-forward answer: like most everything in tech, it’s a matter of weighing benefits and tradeoffs.

In any case, here are some thoughts I’d like to share:

  • Corepack has made Volta less appealing. Volta’s appeal comes from great management of package managers (npm and Yarn). Today, Node.js’s built-in Corepack can do all of that and more.

  • Mise is very promising. Mise’s asdf compatibility was just the beginning, it has more integrations in the works. I see Mise has the potential to evolve beyond version management into a lightweight reproducible dev environment utility, rivaling (or even augmenting) something like devcontainers.

  • The only thing missing from Mise is npm. Corepack on Mise already allows for seamless Yarn and pnpm management… but not npm. Even so, I don’t see this as a dealbreaker. This would only be useful for when an older version of npm may be warranted (eg, with legacy projects).

Should you switch?

If you’re currently using Volta, should you make the switch to Mise? I’d say no, if:

  • You have projects that rely on outdated npm versions, or
  • Need non-WSL Windows support

Or yes if you would like to:

  • Configure Node.js versions in a way compatible with other tools (.node-version)
  • Manage other tools too such as Bun and Deno
  • Use Corepack, which is starting to be a de-facto standard in the community

If you do switch to Mise, keep in mind:

  • Consider Corepack instead of asdf-yarn and asdf-pnpm

Some related reading:

Written by Rico Sta. Cruz

I am a web developer helping make the world a better place through JavaScript, Ruby, and UI design. I write articles like these often. If you'd like to stay in touch, subscribe to my list.

Comments

More articles

← More articles