ASDF: Automatic Management of Multiple Versions
Tags: tooling, programming, webdev, opensource
Published: 2022-04-18 14:31:05

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](#setting-the-scene)
- [ASDF: Our Magic Wand](#asdf-our-magic-wand)
- [An Example](#an-example)
- [Setting Up ASDF](#setting-up-asdf)
- [Usage](#usage)
- [Wrapping Up](#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.

```bash
sudo 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](https://asdf-vm.com/). 🪄


## 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.

```
java openjdk-17
nodejs 17.3.0
postgres 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 really interesting 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.

```
$ node --version
v17.3.0
```

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.

```
$ asdf local nodejs 12.13.0
$ node --version
v12.13.0
```

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

```
$ cd ..
$ node --version
v17.3.0
```

Totally crazy, right? 🤯 Let’s now see how to set-up `asdf` (spoiler alert: 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.

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

> If you are on MacOS, you can simply use `brew`.
> 
> ```
> brew install asdf
> ```

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

```
. $HOME/.asdf/asdf.sh
. $HOME/.asdf/completions/asdf.bash
```

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


## Usage

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:

```
asdf plugin add [plugin]
```

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

```
asdf 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`.
> 
> 
> ```
> asdf 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.

```
asdf install nodejs 12.13.0
asdf 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.

```
asdf 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 sub-directories. 🥳

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.

```
nodejs 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.

```
asdf global nodejs 17.3.0
```

> 💡 You can also specify a version for the current shell.
> 
> 
> ```
> asdf 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](https://asdf-vm.com/). Also, feel free to star the [GitHub Repository](https://github.com/asdf-vm/asdf) 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. 🤘🏼

## More Articles From Me

{% post iamludal/custom-react-hooks-useinview-36m9 %}

{% post iamludal/why-your-github-profile-sucks-1ph9 %}

{% post iamludal/taking-console-log-to-the-next-level-48c9 %}