asdf-vm Guide: One Version Manager to Rule Them All (Node, Python, Go, and Ruby)

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

The version manager fatigue

DevOps engineers and full-stack developers often end up as accidental collectors of version managers. One Node.js project demands version 20, but a legacy script breaks on anything older than 14. Your Python automation relies on 3.11, while a client’s tool is stuck on 3.8. To cope, you likely have nvm, pyenv, rbenv, and gvm all fighting for space in your shell config.

My .zshrc used to be a graveyard of initialization scripts. Every new terminal tab took 1.5 to 2 seconds to load as each manager performed its own slow handshake. On an Ubuntu 22.04 server with only 4GB of RAM, this overhead isn’t just annoying—it’s a waste of cycles. asdf-vm solves this by providing a single, extensible CLI to manage almost any runtime.

Instead of learning five different CLI syntaxes, you only need one tool. It uses a plugin system to handle everything from languages to specialized CLI tools like Terraform or kubectl.

How asdf works (without the fluff)

The core appeal of asdf is its plugin architecture. It doesn’t try to be a specialized Node or Python manager. Instead, it acts as a generic wrapper. Each plugin is a community-maintained script that knows exactly how to fetch and compile a specific language version.

Three layers define the asdf workflow:

  • Plugins: Scripts for specific tools (e.g., nodejs, python, ruby, golang).
  • Versions: The specific releases you choose to install on your machine.
  • Scopes: Global settings for your entire user account and Local settings for specific project directories via a .tool-versions file.

Installation: The Git method

Installing via Git is the smartest move because it makes future updates a one-line command. First, grab the essential build tools. On Debian-based systems like Ubuntu or Mint, run:

sudo apt update && sudo apt install curl git -y

Next, clone the asdf repository into your home directory. I recommend the latest stable branch (v0.14.1 as of this writing):

git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.14.1

Configuring your shell

You need to tell your shell where to find the asdf binaries. For Bash, add these lines to your ~/.bashrc:

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

Zsh users should add this to ~/.zshrc:

. "$HOME/.asdf/asdf.sh"

Reload your configuration with source ~/.zshrc (or ~/.bashrc) and verify the setup by running asdf version.

Hands-on: Setting up your environment

An empty asdf installation is just a shell. You need to populate it with the languages you actually use. Here is a typical stack for a modern development environment.

1. Node.js

Add the plugin and install two different versions—perhaps the current LTS and an older release for a legacy project:

asdf plugin add nodejs
asdf install nodejs 20.11.1
asdf install nodejs 18.19.0

2. Python

Python usually needs to be compiled from source to ensure it integrates perfectly with your Linux kernel. Install the build dependencies first to avoid errors:

sudo apt install build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev curl libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev -y

asdf plugin add python
asdf install python 3.12.2
asdf install python 3.10.13

Switching versions seamlessly

This is where asdf replaces manual effort with automation. You define versions at two levels to stay organized.

The Global Default

Set your primary versions for general use whenever you aren’t in a specific project folder:

asdf global python 3.12.2
asdf global nodejs 20.11.1

The Project-Specific Override

Suppose ~/projects/legacy-app needs Node 18. Navigate there and lock it in:

cd ~/projects/legacy-app
asdf local nodejs 18.19.0

Asdf writes this to a .tool-versions file in that folder. Now, the moment you enter that directory, node -v will switch to 18.19.0 automatically. When you leave, it snaps back to your global default of 20.11.1. No more manual nvm use commands every time you switch tasks.

Managing Go and Ruby

The workflow remains identical for every other language. To set up Go:

asdf plugin add golang
asdf install golang 1.22.0
asdf global golang 1.22.0

For Ruby (which requires libyaml-dev and other build tools):

asdf plugin add ruby
asdf install ruby 3.3.0
asdf local ruby 3.3.0

Updating everything at once

Maintenance is often the hidden cost of development tools. With asdf, you can refresh the core tool and every single language plugin with two quick commands:

asdf update
asdf plugin update --all

This centralized management simplifies disaster recovery. If you move to a new laptop, just copy your .tool-versions file, run asdf install, and your entire environment is rebuilt in minutes. It guarantees that your local setup is a bit-for-bit match with your production servers.

Final thoughts

Migrating to asdf-vm might feel like another task on your to-do list, but it’s an investment that pays off daily. You get a cleaner shell, a consistent command set, and a foolproof way to sync environments with your team. If you are tired of version manager sprawl on Linux, this is the solution you’ve been looking for.

Share: