How to Manage Multiple Runtime Versions With a Single Tooling
Tags: tooling, development
Published: 2021-07-08 13:10:54

> Photo by <a href="https://unsplash.com/@nananadolgo?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Nana Smirnova</a> on <a href="https://unsplash.com/@nananadolgo?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
  

Hey, devs.

Today I want to present to you a simpler and (IMO) better way to have installed different versions of the same runtime in your machine with a single tool called `asdf`.

The tool itself is relatively simple, the docs are well written and you won’t have trouble getting started asap.

Here I will just make a summary and present you some gotchas I had after a while using it.

---

## The Hell of Runtime Versions

Back in 2013 when I was learning development in college, I remember having a lot of trouble running some projects because they rely on a specific Java version.

“Oh, this one uses Java 5, I need to download the runtime. But wait, I already have Java 6 in my machine… damn”

This was very overwhelming, especially because I didn’t have much experience and back then my professors and colleagues didn’t know a better way of easing this problem.

In the first company I started work as a software developer, all backend apps were written in ruby and well… the exact same problem.

To avoid consuming the production/staging environment while I was coding my client-side application, I needed to run a couple of servers in my machine and, again, they required different ruby versions.

Luckily the backend team had a wiki page recommending to use a tool called RVM (Ruby Version Manager), which as the name already explains itself, is a CLI to control multiple ruby versions in our machine.

And it worked pretty well, to be honest.

After a while coding front-end applications, I started to see more often the same problem happening with node js.

> This project uses node 7. But I have node 10 installed... Oh no…

When I googled to find a similar solution as `rvm`, I found NVM (Node Version Manager), which does the same thing as `rvm` but for the Node runtime.

Ok, now I have 2 CLIs to handle the same problem.

It was then I started to study Go and thought: “oh, here we go again… another CLI”.

After I complained about that to a colleague he said:

> Why the heck don't you use `asdf` for all these languages?

And my mind explodes because of course, if I was bothered dealing with that, someone in the plant was bothered as well, and most importantly: he/she had already created a tool that solves this problem.

---

## The Master CLI: asdf

`asdf` is a CLI tool that solves the runtime version management in a well-architected and elegant way: by being a single tool for all runtimes.

The idea is that `asdf` is a core application that does the handling heavy-lifting of providing CLI options, being hooked via terminal, etc. but instead of also solving the version available for **every single runtime that exists**, it delegates this to third party plugins.

![asdf workflow](https://res.cloudinary.com/duzei21zt/image/upload/v1625743285/site/asdf_1_4ab74a00a5.png)

This means that `asdf` does not care about any runtime like java, go, deno, rust, or whatever, but it provides an abstract interface where someone in the community can simply create and maintain a plugin that provides all the information to download the version X for example.

If you’re familiar with Front-end development, this is pretty much like babel does. It handles our code but you can write your plugin that hooks there and do something else without creating a burden to the Babel’s team to maintain the code itself.

The following sections will show how the tooling works. If you want to try, you need to make sure that you have `asdf` properly installed and configured in your bash, fish, or zsh terminal configuration.

> [asdf installation guide](https://asdf-vm.com/#/core-manage-asdf?id=install)

### Plugins

As I mentioned, a plugin is a specific runtime manager. In that sense, the `asdf-ruby` plugin only deals with how to download ruby runtime, which version was released, etc.
Installing a plugin is relatively easy but I strongly recommend you check the plugin’s repository and see if there are more instructions needed before adding it.

> Check here [all plugins available](https://asdf-vm.com/#/plugins-all) for `asdf`

In general, the instruction follows the same basic way of installing, running `asdf plugin add <plugin-name> <git-url>`. The `git-url` isn’t required but recommended just to be sure you’re consuming for the correct repository:

```bash
asdf plugin add nodejs
asdf plugin add ruby https://github.com/asdf-vm/asdf-ruby.git
```

Now, my `asdf` will have 2 plugins: one capable to manage node versions and another to manage ruby versions.

### Versions

The plugin itself won’t add any version by default. It’s time to finally install some versions we want to use in some projects.

For this example I want to have in my machine:
Latest `10.2` version of node
Latest `14` version of node
Exact `2.6.5` version of Ruby
Latest `2.7` version of Ruby

For all these versions I'll run `asdf install <plugin-name> <version>`. So all I need to do is running in the terminal:

```bash
asdf install nodejs latest:10.2
asdf install nodejs latest:14
asdf install ruby 2.6.5
asdf install ruby latest:2.7
```

> Obs.: depending on your environment you might need to install some stuff before being able to install a runtime, like ruby for example that requires having `libssl-dev`, etc, in a Linux machine before installing successfully.

Note that since in some cases we didn't care about the exact version we simply specified a `latest:` prefix before the version number and this will end up installing the latest version available for that number.

Now if we want to know the versions installed, we can simply run `asdf list <plugin-name>`:

```text
asdf list nodejs
 10.24.1
 14.17.3
 
asdf list ruby
 2.6.5
 2.7.4
```

### Defining a runtime version

There are 2 cases where you want to define a version: for global and local scope.

#### Global

We always need to define a version for the global context. Personally, I like to use the latest LTS version of NodeJS (today 14.17) by default and fallback down depending on the project

To do that all I need to do is running `asdf global <plugin-name> <version>`:

```bash
asdf global nodejs 14.17.3
```

Now if I check my node version it'll show this specific version:

```text
node -v
v14.17.3
```

#### Local

And now, back to the main problem, we're trying to solve: running a specific version for a specific project.

For specifying a local version, all we need to do is to run `asdf local <plugin-name> <version>`:

```bash
asdf local nodejs 10.24.1
```

By doing that, `asdf` will create a file in the folder you’re called `.tool-versions` that contains the following content:

```text
nodejs 10.24.1
```

Now, every time I run `yarn start` for example (which will invoke somehow node runtime) because `asdf` is intercepting the call and finds this file, it’ll use version `10` instead of my global `14`.

> Tip: if for some reason you don't want to commit the `.tool-versions` file you can either add it in the `.gitignore` of your project or if this rule will be applied to all projects, setting this ignore globally like [I explain here](https://raulmelo.dev/til/how-to-set-a-global-gitignore)

### Removing a plugin

Let's say now you left the company and will no longer need `ruby` versions in your machine.

All you need to do is by simply removing the plugin with `asdf plugin remove <plugin-name>`:

```bash
asdf plugin remove ruby
```

BY doing that, the `ruby` plugin and all versions we've installed in the previous steps will be completely removed from our machine.

### Compatibility

If you already are using another tooling and want to migrate to `asdf` without having to remove the existing version file, in your $HOME path you can create a file called `.asdfrc` and add the flag legacy version file:

```
legacy_version_file = yes
```

> More info: https://asdf-vm.com/#/core-configuration?id=tool-versions


---

## Conclusion

I hope now it’s clear to you how awesome `asdf` is not only to solve this cumbersome version problem but also in terms of using a very robust plugin mechanism for the correct problem.

Any questions or comments, please reach out on Twitter.

Cheers.

---

## References

- [https://asdf-vm.com/](https://asdf-vm.com/)