DEV Community

Cover image for mise vs. asdf for JavaScript project environment management
Megan Lee for LogRocket

Posted on • Originally published at blog.logrocket.com

mise vs. asdf for JavaScript project environment management

Written by Rosario De Chiara✏️

mise and asdf are tools designed to help developers manage multiple versions of programming languages and environments. Both tools aim to simplify polyglot development by making it easier to manage and switch between tool versions, which is a common challenge when working with different programming languages and frameworks.

What is asdf?

asdf is a popular version manager that uses a technique called "shimming" to switch between different versions of tools like Python, Node.js, and Ruby. It creates temporary paths to specific versions, modifying the environment to ensure that the correct version of a tool is used in different projects. However, this method can introduce performance overhead due to how these shims work.

What is mise?

mise, short for the French expression “mise-en-place,” which is how you prepare a table, seeks to improve on asdf by removing the reliance on shims.

Written in Rust, mise directly modifies the PATH environment variable, leading to faster execution times. It is designed to work seamlessly with asdf plugins but offers features like fuzzy matching of commands and the ability to install multiple versions of the same tool simultaneously.

Getting started with asdf

To install asdf, follow the getting started guide to install prerequisites depending on your system. Once the environment is ready, you can git clone the official repository in your home directory:

 $ git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.14.1
Enter fullscreen mode Exit fullscreen mode

The command above will clone into the .asdf directory all the script and configuration files needed to finalize the installation.

The next step, from the installation guide above, is to execute the installation script. Again, this step will depend on the details of your environment and operating system, so just follow the guide to add the proper script invocation in your shell initialization script (e.g., .bashrc, .bash_profile, etc.). At the end of this process and, typically after you restart your shell, you should be able to run asdf as a command:

ASDF Plugin List

At this point, asdf is running but to make something useful with it, you must install the plugins to handle the tool (in the asdf parlance) that are relevant for the project you intend to develop (e.g., Node.js, python, etc.).

For this purpose, we install the plugin for Node.js. In asdf, a plugin is the piece of code that will let you juggle different versions of a framework or library. In this case, we'll install the Node.js plugin and then install a couple of versions of Node.js just to understand how asdf will handle them.

We’ll install the Node.js plugin with the following code:

 $ asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git
Enter fullscreen mode Exit fullscreen mode

Please note that you have to explicitly address the git repository containing the plugin source code. Once the plugin is in place, you can use it to install specific versions of Node.js with the following command:

 $ asdf install nodejs latest
Enter fullscreen mode Exit fullscreen mode

In this example, you install the latest version which, at the time of writing, is 23.1.0. With the following command, you install a specific version of Node.js:

 $ asdf install nodejs 20.0.0
Enter fullscreen mode Exit fullscreen mode

To check that both are available in your system, use the following:

 $ asdf shim-versions node
 nodejs 20.0.0
 nodejs 23.1.0
Enter fullscreen mode Exit fullscreen mode

To select the version of Node.js to use, use the following command:

 $ asdf global nodejs 20.0.0
 $ node --version
 v20.0.0
 $ asdf global nodejs 23.1.0
 $ node --version
 v23.1.0
Enter fullscreen mode Exit fullscreen mode

asdf handles the various versions of a tool by populating a file named [.tool-versions](https://asdf-vm.com/manage/configuration.html#tool-versions) with the following format:

ruby 2.5.3
nodejs 10.15.0
Enter fullscreen mode Exit fullscreen mode

The file .tool-versions is manipulated automatically by asdf with the command to specify which version of a given you intend to use, as we did above with Node.js version 20.0.0. Depending on the parament global, shell, and local, we will add the versions of a tool to a specific .tool-versions file with different effects on your environment. Following, there is the explanation of the impact of the parameters in case we install Node.js version 20.0.0:

  • asdf global nodejs 20.0.0: In this case, we intend to use this specific version throughout the system wherever it is not specified differently
  • asdf shell nodejs 20.0.0: This is the case where we want to use this version of Node.js just for the current shell session
  • asdf local nodejs 20.0.0: This flavor of the command will create a .tool-versions that specifies the version of Node.js only valid for the directory where the command is executed. This means that we can have different versions of the same tool in different sub-directories of your project. This is a pretty neat feature, relevant for complex projects. In the following image, you can see how this affects your environment:
 ~$ asdf local nodejs 20.0.0
 ~$ node --version
 v20.0.0
 ~$ mkdir test
 ~$ cd test
 ~$ asdf local nodejs 23.1.0
 ~$ node --version
 v23.1.0
 ~/test$ cd ..
 ~$ node --version
 v20.0.0
Enter fullscreen mode Exit fullscreen mode

With the first command, we tell asdf to use version 20.0.0 in the home directory and node --version confirms the version. Then, we create a directory named test. In test, we execute asdf, specifying a different version for Node (version 23.1.0) and, again, the node --version confirms that we are using version 23.1.0. Finally, getting back to the home directory, you can see how the version of Node.js locally is still 20.0.0.

What is a shim?

Now that we have asdf working on our system, let’s learn what a shim is and why it matters when working with asdf.

In computer science, a shim is a way of redirecting commands (e.g., library methods invocation) transparently between different versions. The key here is the word “transparently.” The whole idea of asdf is to allow the user to change what is really called when you write, let's say, node or python or any other package, in a transparent way. The user keeps typing node or python but asdf has set up a different path – a shim – to the correct version depending on what is written in the .tool-versions file.

A plugin is just a set of clever shell scripts that let asdf select the proper version of a specific command (e.g., check the Node.js plugin). The commands in the bin directory just implement what asdf must execute when you use the Node.js plugin to install a new version, select a specific version for use, etc.

Getting started with mise

The process of installing mise is easier compared to asdf because you won’t need to clone a git repository:

 $ curl https://mise.run | sh 
Enter fullscreen mode Exit fullscreen mode

The activation guide is pretty simple; once you execute the command above and restart your shell, you will be able to run the following:

 $ mise doctor
Enter fullscreen mode Exit fullscreen mode

This will show the status of your installation. Once mise is installed, you might need to activate it with the [mise activate](https://mise.jdx.dev/cli/activate.html) command.

At this point, the mise command is available to be used for the most common task: installing a specific version of a framework to make it globally available for the system:

 $ node
 Command 'node' not found, but can be installed with:
 sudo apt install nodejs
 $ mise use --global node@22
 mise ~/.config/mise/config.toml tools: node@22.11.0
 $ node
 Welcome to Node.js v22.11.0.
 Type ".help" for more information.
 >
Enter fullscreen mode Exit fullscreen mode

We start from a situation where the node executable is not in the system. Using the mise command, we install a specific node version globally to make it available. To verify the versions of the tools currently installed, you can use the following command:

 $ mise list
 Tool    Version  Config Source              Requested
 node    22.11.0  ~/.config/mise/config.toml 22
 python  3.13.0
 $
Enter fullscreen mode Exit fullscreen mode

In the command above, you can see the node tool installed in the box above and a Python version.

Comparing asdf vs. mise

The mise framework uses the same asdf mechanism to handle the different configurations of tools throughout the system and within specific directories. The role of the .tool-versions file in asdf is played by the mise.toml file, which will collect the configurations.

In mise, there is no concept similar to asdf plugins, and this is a good thing because, while in asdf, installing a specific version of a tool – let’s say node@20.0.0 – is a two-step process (first installing the Node.js plugin and then the particular version of Node). In mise, you simply address the single version of the tool you need, and mise will handle all the heavy lifting of configuring it for you behind the scenes. In the following two boxes, you can see how the asdf commands translate to mise:

 asdf plugin add node
 asdf install node latest:20
 asdf local node latest:20
Enter fullscreen mode Exit fullscreen mode

In mise, this can all be done in a single step that installs the plugin and the runtime, and sets the version:

 mise use node@20
Enter fullscreen mode Exit fullscreen mode

The general verbosity of asdf is solved elegantly by the syntactic sugar of mise. Still, mise is different in how it handles the various versions, which has a wider impact on the whole experience. In the following image, we depict what happens when you execute a node command in an environment where asdf is working:

Execute Node Command Environment Where ASDF Is Working

This process, of course, impacts the time required to execute a command. On the other hand, mise solves the same problem of selecting the correct tool depending on the configuration by leveraging another mechanism: the PATH variable, which is the operating system's native mechanism to execute a command.

The performances are identical to running the command (e.g., node) without using mise. For the sake of curiosity, mise works differently with respect to asdf: mise tracks down every change of directory so that when the user changes the directory, mise invokes an internal hook to update the PATH variable. This hook is very efficient because it is written in Rust and it will set up the PATH variable on the fly to configure your environment.

Conclusion

Both asdf and mise effectively manage multiple tool versions, each with unique mechanisms. mise excels in efficiency thanks to its PATH hook mechanism, while asdf offers broader tool compatibility but with the performance trade-off of its shim mechanism. mise's compatibility with asdf plugins bridges the gap between the tools.

Whether prioritizing speed or selection, both tools empower developers to manage their environments with ease, offering a flourishing ecosystem for various packages and tools.


Get set up with LogRocket's modern error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID.
  2. Install LogRocket via NPM or script tag. LogRocket.init() must be called client-side, not server-side.

NPM:

$ npm i --save logrocket 

// Code:

import LogRocket from 'logrocket'; 
LogRocket.init('app/id');
Enter fullscreen mode Exit fullscreen mode

Script Tag:

Add to your HTML:

<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
Enter fullscreen mode Exit fullscreen mode

3.(Optional) Install plugins for deeper integrations with your stack:

  • Redux middleware
  • ngrx middleware
  • Vuex plugin

Get started now.

Top comments (0)