asdf is a language-agnostic tool for managing multiple runtimes of a specific tool for a particular user. While it is able to manage runtime versions for a user, it is particularly helpful for managing runtimes per project. Tools like rbenv, pyenv, nvm, goenv, and the like each solve this problem for a particular language runtime. This quickly becomes a headache for the polyglot.

Enter asdf, a single tool with a plugin architecture which makes management of various language runtimes a breeze. Its plugin architecture provides plugins for more than just language runtimes. I use it in C++ projects to manage various build dependencies, including ccache, CMake, and ninja.

How It Works

Like it’s language specific counterparts mentioned previously, asdf determines the appropriate runtime version to use by integrating with a user’s shell and inserting shims into the user’s PATH. Each shim executable, such as the ruby shim, defers the call of the actual program to asdf, which then executes the appropriate version.

asdf determines the version from the first configuration information it finds searching three specific places.

asdf Version Selection
  1. shell: The environment variable ASDF_${LANG}_VERSION is checked for the version of a particular asdf plugin.

  2. local: The current directory, followed by subsequent parent directories, are searched for the special .tool_versions file.

  3. global: Versions are configured for a particular user in a .tool_versions file in her home directory.


This tutorial describes the basics for managing a project’s runtimes with asdf. This is accomplished on an Ubuntu 20.04 system. While these instructions are for specifically for the fish shell, the asdf documentation contains the necessary steps for other shells. This tutorial assumes you are comfortable with Git, package installation on Ubuntu, and the command-line on Unix-like systems.


  1. Install the dependencies needed for asdf.

    sudo apt -y install curl git
  2. Pull down the asdf repository in to your home directory.

    ➜ git clone ~/.asdf
  3. Checkout the latest version of asdf.

    ➜ git -C ~/.asdf switch --detach (git -C ~/.asdf describe --abbrev=0 --tags)
    HEAD is now at c6145d0 Update version to 0.8.0
  4. Enable asdf for the fish shell.

    mkdir -p ~/.config/fish/conf.d; and echo "source ~/.asdf/" > ~/.config/fish/conf.d/
  5. Install shell completions for asdf.

    mkdir -p ~/.config/fish/completions; and ln -s ~/.asdf/completions/ ~/.config/fish/completions
  6. To make asdf available, restart your terminal.

  7. Add plugins for managing the desired runtimes, such as the Ruby plugin described here.

    Plugins may require certain dependencies be installed on the system, so be sure to check their documentation. In the case of the Ruby plugin, install its dependencies with the following command.

    sudo apt -y install autoconf bison build-essential libssl-dev libyaml-dev \
      libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm6 libgdbm-dev \

    Then add the Ruby plugin with the asdf plugin add command.

    ➜ asdf plugin add ruby

Configure the Project

Now that asdf is installed, it’s time to configure a project to use a specific version of a runtime.

  1. First, install the desired version of said runtime.

    ➜ asdf install ruby latest
    A specific version number can be provided or the latest keyword can be used to automatically install the latest version available.
  2. Next, change to the root directory of the project.

  3. Set the specific runtime version for a project with asdf local.

    ➜ asdf local ruby (asdf latest ruby)

    The asdf local command records the appropriate version for a runtime in a .tool-versions file in the current directory, creating it if it does not exist. At the time of this writing, the latest Ruby version available is 2.7.2, so the previous command creates the following file.

    ruby 2.7.2
Rinse, wash, and repeat for each runtime you wish to configure for your project.


The previous sections result in a complete setup of asdf and the runtime. No more is needed. What about starting with a configured project in a new environment? This is the case when setting up a new machine or when a new developer gets started on the project. The necessary work flow is described step-by-step below.

  1. Install asdf and the required plugins according to the Install section above.

  2. Change into the project directory.

  3. Install all required runtimes.

    ➜ asdf install


Updates are important, so the necessary commands to update asdf and its plugins are provided below.

  1. Update asdf with ease.

    ➜ asdf update
  2. Update the plugins.

    ➜ asdf plugin update --all

Automatic updates can be configured with systemd. See my post Automatically Update Antigen for achieving this in a similar scenario.


You should now understand the basics of how asdf operates, and how to manage runtimes for a project with it.