Cover image

ASDF: Automatic Management of Multiple Versions

Posted on 4/19/2022


Have you ever been in this situation where you are working on multiple projects and have to deal with multiple versions of Java, NodeJS or Postgres? In this article, we’ll discover how to switch between different runtime versions automatically depending on the current folder, and therefore the project. 📁

  • Setting the Scene
  • ASDF: Our Magic Wand
  • An Example
  • Setting Up ASDF
  • Usage
  • Wrapping Up

Setting the Scene

As a freelance developer working on different projects for different clients, you have probably already found yourself in this situation: project A runs with Java 8, project B runs with Java 11, and project C runs with Java 17. To easily switch between these versions, you might have used the update-alternatives command.

1sudo update-alternatives --config java

This works pretty fine, but there is a drawback to this approach: you have to manually run this command every time you have to switch to another version, which can quickly get cumbersome. Also, this command does not work with all tools, such as node or postgres.

One way to solve this problem is to use Docker. Indeed, the purpose of Docker is to create an image that contains all the correct versions for the current project. However, not everyone knows Docker, and not every project has a Dockerfile to build this setup. Also, not all teams have the time to build a Dockerfile: depending on the project size, it can easily get complicated to create one quickly.

Another solution would be to have something like a magic wand that automatically switches between Java 8 in the project-A folder and Java 11 in the project-B folder, and so on.

Actually, this magic wand exists, and is called asdf. 🪄

ASDF: Our Magic Wand

So what really is asdf? It is a CLI tool that automatically switches between your runtime versions (Java, NPM, Node, Postgres, PHP, and even more) depending on your current folder. To do so, it relies on a file named .tool-versions (located in the folders where you need to use it) to know which version to use for each tool. This file simply contains a mapping list of each tool with the correct version to use.

1java openjdk-17
2nodejs 17.3.0
3postgres 13.5

When your current folder does not contain a .tool-versions, asdf will just look in the parent folders to find the first one containing such a file. As a result, you need to define a default version for each tool, so that asdf can use this default version if no .tool-versions file was found in the parent folders. The default versions are stored in your home directory: ~/.tool-versions.

Something fascinating is that you can commit this .tool-versions file to your git repository so that your colleagues can also have the correct versions of the different tools, as long as they are using asdf. 💪🏼

An Example

Let’s say your default node version is 17.3.0, but one of the projects you are working on is a bit old and uses version 12.13.0. If you start a terminal and run the command to get the node version, it will display your current one.

1$ node --version

This command will produce the same output if you are in the project-A folder. However, if you tell asdf that it should use the version 12.13.0 of node in this project, the output will change.

1$ asdf local nodejs 12.13.0
2$ node --version

And if you change to another directory, the node version will magically change back to your default one.

1$ cd ..
2$ node --version

Totally crazy, right? 🤯 Let’s now see how to set up asdf

and it is ridiculously easy

Setting Up ASDF

In the first place, you will need to download asdf (available on Linux and macOS, but unfortunately not on Windows). To do so, just clone the git repository to your home folder.

1git clone https://github.com/asdf-vm/asdf.git ~/.asdf

If you are using macOS, you can simply run brew install asdf.

Once done, you will need to add these two lines to your .bashrc (or .zshrc).

1. $HOME/.asdf/asdf.sh
2. $HOME/.asdf/completions/asdf.bash

And that’s it, you’ve successfully installed asdf! 🎉


To use asdf, you will first need to add the plugins you need. A plugin corresponds to a tool: for instance, you will need to add the java plugin to switch between java versions, the nodejs plugin to switch between NodeJS versions, and so on. To add a plugin, simply run the following command:

1asdf plugin add [plugin]

In this example, we will continue with nodejs, so we will install this plugin.

1asdf plugin add nodejs

You can list all the available plugins with the asdf plugin list all command. As this will produce a pretty big list, you can filter the results with grep.

1asdf plugin list all | grep node

Now that we’ve added the nodejs plugin, we will need to download the versions we want to use. In our case, we want both 12.13.0 and 17.3.0 versions.

1asdf install nodejs 12.13.0
2asdf install nodejs 17.3.0

After installing these versions, the last step is to specify which one to use depending on the project. To do so, head over to the folder of the project that uses 12.13.0 (let’s say project-A) and select the correct nodejs version.

1asdf local nodejs 12.13.0

And that’s it! The 12.13.0 version of Node will be used in the project-A directory and subdirectories. 🥳

If you now run ls -al in the project folder to list all the files, you will notice the .tool-versions file that contains the correct Node version. You can commit it to your version control system.

1nodejs 12.13.0

When cloning the project containing this file, your colleagues don’t even have to manually install the listed versions: they can simply run asdf install, and the magic wand will take care of downloading all required versions.

Lastly, as we’ve seen earlier, we need to define a default version to use when we are in another folder which has no .tool-versions file in it or in its parent folders. In our case, we want the default version of Node to be 17.3.0.

1asdf global nodejs 17.3.0

You can also specify a version for the current shell.

1asdf shell nodejs 17.3.0

And that’s it, we’ve successfully got rid of the pain of having to manually switch between our runtime versions, thanks to our new magic wand. 🪄

Wrapping Up

Thanks to asdf, our runtime versions are now managed automatically. When you need to use a new plugin, the steps will always be the same:

  1. Install the corresponding plugin: asdf plugin add [plugin]
  2. Install all the versions you need: asdf install [plugin] [version]
  3. Select the local version for each concerned project: asdf local [plugin] [version]
  4. Select the default version for this plugin: asdf global [plugin] [version]

For more information, or if you need help on this awesome tool, don’t hesitate to head over to asdf-vm.com. Also, feel free to star the GitHub Repository of asdf to support the team behind this project. 😉

I hope this article was useful to you, and I’ll see you in the next ones. 🤘🏼

Copyright © 2022 Ludovic CHOMBEAU