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
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.
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
asdffor 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.
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.
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.
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 for
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:
asdf plugin add nodejs asdf plugin add ruby https://github.com/asdf-vm/asdf-ruby.git
asdf will have 2 plugins: one capable to manage node versions and another to manage ruby 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:
10.2 version of node
14 version of node
2.6.5 version of Ruby
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:
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>:
asdf list nodejs 10.24.1 14.17.3 asdf list ruby 2.6.5 2.7.4
There are 2 cases where you want to define a version: for global and local scope.
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>:
asdf global nodejs 14.17.3
Now if I check my node version it'll show this specific version:
node -v v14.17.3
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>:
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:
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
Tip: if for some reason you don't want to commit the
.tool-versionsfile you can either add it in the
.gitignoreof your project or if this rule will be applied to all projects, setting this ignore globally like I explain here
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>:
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.
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
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.