Managing Multiple Tool Versions with asdf

A DevOps Essential

assorted color plastic tools on gray wooden table

Photo by Dan Cristian Pădureț on Unsplash

As a DevOps engineer, working across multiple projects often means juggling different versions of programming languages, infrastructure tools, and CLIs. Using system-wide installations can quickly lead to version conflicts. Enter asdf (Another Shell Development Framework), a powerful version manager that simplifies this process by managing multiple tool versions per project.

In this article, we’ll cover:

  • Why asdf is useful
  • Installing asdf
  • Managing Go and Terraform versions
  • Automating asdf install when entering a Git repository

Why Use asdf?

There are several tools like nvm for Node.js, pyenv or poetry for Python, and gvm or goenv for Go. However, asdf offers a unified approach:

  • Single tool for multiple languages and CLIs (Go, Terraform, Ansible, Node.js, Python, etc.)
  • Project-specific version management via a .tool-versions file
  • Lightweight and portable—works on macOS, Linux, and WSL
  • Plugin-based architecture—supports a wide range of tools via plugins
  • Easy version switching—switch between different versions per project or globally

What are common Use Cases?

asdf shines in environments where multiple projects depend on different versions of programming languages or tools. Here are some common use cases:

  1. Microservices Architecture

When working with microservices, each service might require a different version of Go or Node.js. With asdf, you can specify the required version per project using a .tool-versions file. This prevents version conflicts and ensures consistent builds.

  1. Legacy Projects

Maintaining legacy applications often requires using outdated versions of tools. asdf allows you to easily switch to the necessary version without affecting newer projects.

  1. CI/CD Pipelines

In CI/CD workflows, consistent environments are crucial. By defining versions in a .tool-versions file, developers and CI pipelines use the same tool versions, reducing the ‘it works on my machine’ issue.

  1. Open Source Contributions

Contributing to open-source projects often means adhering to specific versions listed in .tool-versions. asdf makes it easy to switch between versions, facilitating a smoother development experience.

  1. Multi-Cloud Infrastructure Automation

For DevOps engineers working with Terraform, different cloud environments may require different provider versions. asdf allows you to manage these versions effortlessly, avoiding provider version conflicts.

By addressing these use cases, asdf ensures consistency, reduces conflicts, and enhances productivity for both developers and DevOps engineers.

Installing asdf

Before using asdf, install it on your system.

macOS (with Homebrew)

brew install asdf

Linux

git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.12.0
echo '. $HOME/.asdf/asdf.sh' >> ~/.bashrc
source ~/.bashrc  # or 'source ~/.zshrc' if using zsh

Archlinux

# Use an aur helper
yay asdf-vm

for other ways installing asdf you need to read the doc Install asdf.

Configure asdf

This section is adapted from the `asdf` getting started guide. For more detailed information, please refer to the documentation.

Bash Configuration

If you are using macOS Catalina or newer, the default shell has changed to ZSH. If you prefer to continue using Bash, follow these steps:

If you’re on a system using Pacman (e.g., Arch Linux), make sure bash-completion is installed for completions to work properly.

To add the shims directory to your path (required), add the following to your ~/.bash_profile:

export PATH="${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH"

Custom Data Directory (Optional) If you want to use a custom data directory, add the following line above the one you just added:

export ASDF_DATA_DIR="/your/custom/data/dir"

ZSH

For ZSH users, add the following to your ~/.zshrc:

export PATH="${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH"

Custom Data Directory (Optional) To specify a custom data directory in ZSH, add the following above the previous line:

export ASDF_DATA_DIR="/your/custom/data/dir"

This setup ensures that asdf shims are prioritized in your PATH, enabling seamless version management.

Before using asdf, install it on your system.

Managing Go and Terraform with asdf

asdf offers first-party plugins and a large community of contributors, you can take a look into the asdf-community plugins. If you don’t find a plugin for your use case, consider creating your own Plugin from the asdf-plugin-template.

Install the Required Plugins

To manage different versions of Go, Terraform, add their plugins:

asdf plugin add golang                                                                                      
asdf plugin add terraform https://github.com/asdf-community/asdf-hashicorp.git

Install Latest Versions

After adding plugins, you can install the latest versions.

asdf install golang latest
asdf install terraform latest

Install Specific Versions

Now install the versions needed for your projects.

asdf install golang 1.23.4
asdf install terraform 1.10.0

To set a global default version:

asdf set -u golang latest
asdf set -u terraform latest

this will create a file in your home directory, which holds the global versions:

❯ cat ~/.tool-versions
golang 1.24.0                                              
terraform 1.10.5

To set a project-specific version, run the following inside a project folder:

asdf set golang 1.23.4

This creates a .tool-versions file in the directory, ensuring the correct versions are used when working inside the project.

IDEs

Some IDEs, like IntelliJ IDEA, can detect .tool-versions and automatically use the version specified by asdf. This integration ensures consistency between your terminal and IDE without manually configuring versions.

By leveraging asdf with your IDE, you avoid the hassle of downloading and managing multiple versions within the IDE itself. This approach keeps your environment clean, ensuring your terminal and IDE are always in sync with the right versions.

Shows an Intellij Idea config window, that configures go version by asdf tools-version

Verify Installed Versions

To check which version is currently active in your home directory:

❯ cd ~
❯ cat .tool-versions
golang 1.24.0
terraform 1.10.5
❯ go version
go version go1.24.0 linux/amd64
❯ terraform version
Terraform v1.10.5
on linux_amd64

To check which version is currently active in your project directory:

❯ cd gofrommediumtohugo
❯ cat .tool-versions
golang 1.23.4
❯ go version
go version go1.23.4 linux/amd64

If you frequently switch between projects, you can automatically install the required versions whenever you cd into a Git repository.

Add the Following Function to

cd() {
    builtin cd "$@" || return
    
    if git rev-parse --is-inside-work-tree &>/dev/null; then
        if [ -f .tool-versions ]; then
            echo "🔍 Detected .tool-versions file. Running asdf install..."
            asdf install
        fi
    fi
}

Reload Your Shell

source ~/.zshrc

How It Works

  • Every time you use cd, the function checks if the directory is inside a Git repository.
  • If a .tool-versions file is found, asdf install runs automatically to ensure all necessary versions are installed.
  • This eliminates manual intervention when switching projects!

Keeping asdf and Plugins Updated

To keep asdf and all installed plugins up to date, run: Upgrading asdf via asdf update is no longer supported. Please use your OS package manager (Homebrew, APT, etc…) to upgrade asdf or download the latest asdf binary manually from the asdf website.

Please visit https://asdf-vm.com/ or https://github.com/asdf-vm/asdf for more details.

asdf plugin update --all

Troubleshooting and Clearing Cache

If you encounter issues with asdf, such as plugins not working correctly or version conflicts, clearing the cache and updating plugins can often resolve the problem.

Common Issues

  • Command Not Found: Occurs when shims are outdated or missing.
  • Version Conflicts: Happens when switching between multiple projects with different tool versions.
  • Plugin Failures: Sometimes a plugin may not work as expected due to outdated files or dependencies.

How to Clear Cache and Reshim

To resolve these issues, follow these steps:

  1. Update All Plugins

    Keep all plugins up to date to ensure compatibility and stability:

    asdf plugin update --all
    
  2. Clear Cache and Reshim

    After updating plugins, regenerate the shims to ensure correct version mappings:

    asdf reshim
    

    This step rebuilds all executable shims and fixes any broken links, ensuring that the correct version is used in your terminal.

Best Practices

  • Run asdf plugin-update --all regularly to keep plugins up to date.
  • Always follow up with asdf reshim after installing or updating versions.
  • If issues persist, try reinstalling the specific version or clearing the shims directory manually:
rm -rf ~/.asdf/shims/*
asdf reshim

These steps should help you maintain a smooth workflow with asdf, minimizing version conflicts and ensuring consistent behavior across all projects.

Conclusion

asdf is a nice-to-have tool for DevOps engineers and developers who work with multiple tools and languages. It simplifies version management, avoids conflicts, and ensures project consistency across machines.

Why Choose asdf?

  • One tool for multiple runtimes (Go, Terraform, Ansible, and more!)
  • Per-project version management
  • Easy installation and updates
  • Automation-friendly

With the automated installation function for Git repositories, you can focus on coding instead of managing versions manually.

Try asdf today and make your DevOps workflow more efficient!

Sources & Further Reading

Don’t Trust Me — Seriously

The author takes no responsibility for any mishaps, broken servers, or existential crises caused by following this information.

If you spot a mistake, have a better way of doing things, or just want to chat about tech, feel free to reach out.

Also, this isn’t an ad — unless my enthusiasm and advocacy for cool stuff count as advertising.