Introduction to asdf
As projects grow, managing different runtimes gets messy. Your Rails app might need Ruby 3.2, a microservice needs Node 18, and a data pipeline needs Python 3.11. Normally you would install separate tools like rbenv, nvm, and pyenv, each with its own setup.
asdf makes this easier by handling all runtimes with one tool. Instead of juggling different managers, you get a single, consistent interface for everything from Ruby to Terraform.
This guide shows you how to install asdf, use its plugins, and manage multiple runtimes smoothly across your projects.
Prerequisites
This article assumes you are on a Linux or macOS system and can use Homebrew. Windows users can access asdf through Windows Subsystem for Linux. Basic command-line familiarity helps, though we'll explain each step clearly.
Before installing asdf, check the official installation guide for system-specific requirements or alternative installation methods for your operating system.
asdf handles runtime installation completely, so you don't need languages pre-installed. The tool downloads, compiles, and configures everything through its plugin system.
Why choose asdf?
Before diving into installation, let's understand what sets asdf apart from language-specific version managers. The tool operates on a plugin architecture that extends to any runtime or tool you need.
Traditional version managers focus on single languages. Working across multiple languages means installing rbenv, nvm, pyenv, and goenv, each with different commands and behaviors. asdf eliminates this friction by providing one consistent command structure across all runtimes.
The plugin system isn't limited to programming languages. You can manage database versions (PostgreSQL, Redis), infrastructure tools (Terraform, kubectl), and build tools (Maven, Gradle) through the same interface. Each plugin follows asdf's conventions, so learning one teaches you how to use them all.
asdf provides three version scopes: global, project-level, and shell-level (current terminal session only). This flexibility helps when testing across versions or temporarily using different runtimes without affecting your project configuration.
The tool stays lightweight by installing only the plugins you actually use, starting minimal and growing based on your needs.
Installing asdf
Installing asdf with Homebrew is straightforward. Homebrew handles the installation and makes updates simple.
Install asdf using Homebrew:
This installs the latest version of asdf along with its core dependencies. Homebrew places asdf in its standard installation directory and manages the binary for you.
Configure your shell to load asdf. For bash users, add this line to ~/.bashrc:
This loads asdf automatically when you start a new bash session.
If you're using zsh, add this to ~/.zshrc:
For zsh completions, Homebrew handles the setup if you have completion support configured. If you need to set it up manually:
Restart your terminal or source your shell configuration:
Verify asdf installed correctly:
This confirms asdf is installed and accessible. You now have the core tool ready, though you haven't installed any plugins yet.
To update asdf in the future, use Homebrew:
This keeps asdf up to date with the latest features and bug fixes.
Installing and managing plugins
Before you can install any runtime versions, you need to add plugins for the tools you want to manage. asdf maintains an official plugin repository with hundreds of available plugins.
List available plugins:
This displays all plugins in the official repository, showing plugin names and their repository URLs. The list includes major languages, databases, and tools commonly used in development.
Add a plugin for Ruby:
asdf clones the Ruby plugin repository into your plugins directory. The plugin is now available but hasn't installed any Ruby versions yet.
Add plugins for other tools you need:
List your installed plugins:
Each plugin manages its own set of versions independently. You can now install specific versions of Ruby, Node.js, and Python through asdf.
Update plugins periodically to get support for new runtime versions:
Or update all plugins at once:
Plugins occasionally need updates as new versions of runtimes are released or installation methods change.
Remove plugins you no longer need:
This removes the plugin and all versions you've installed through it, so use this carefully.
Installing runtime versions
With plugins installed, you can now install specific versions of runtimes. asdf provides a consistent interface regardless of which runtime you're installing.
List available versions for a plugin:
This displays all Ruby versions the plugin knows about, including stable releases, preview versions, and older versions. The list can be long, so you might want to filter it:
Install a specific version:
asdf downloads the Ruby source, compiles it, and installs it in the asdf directory structure. Compilation takes several minutes depending on your machine.
Install multiple versions:
List installed versions for a plugin:
The output shows which versions you've installed locally. None are active yet because you haven't set any defaults or project-specific versions.
Uninstall versions you no longer need:
This removes the installation directory and frees disk space. Each version typically consumes several hundred megabytes.
Setting runtime versions
After installing versions, you need to tell asdf which versions to use in different contexts. asdf provides three levels of version specification, each serving different purposes.
Set a global default version by creating a .tool-versions file in your home directory:
The -u flag tells asdf to set the version in your user home directory (~/.tool-versions), making Ruby 3.4.6 your default Ruby version across all projects. Global versions provide a fallback when no project-specific version exists.
Verify the version is active:
Check which version is currently active:
Set multiple global versions at once:
Each runtime maintains its own global version independently.
For project-specific versions, navigate to your project directory and set a local version:
This creates a .tool-versions file in the current directory:
The .tool-versions file should be committed to version control. When team members with asdf clone your repository, they'll automatically use the correct versions when working in that directory.
Add multiple tools to the same file:
The .tool-versions file now specifies versions for all three runtimes your project needs.
Test automatic version switching by navigating between directories:
The version switches automatically based on the .tool-versions file asdf finds in each directory.
For temporary version overrides in your current shell session, set an environment variable:
This sets Ruby 3.2.2 for the current terminal session only. The setting disappears when you close the terminal or open a new one. Environment variables help when testing across versions without modifying configuration files.
Working with legacy version files
Many projects use version files from other version managers like .ruby-version, .node-version, or .python-version. asdf can read these files, maintaining compatibility with existing projects.
Enable legacy version file support by configuring asdf:
Now asdf will check for legacy version files when determining which version to use. If it finds both .tool-versions and .ruby-version in the same directory, .tool-versions takes precedence.
Test this with a Ruby project. First, unset any environment variables:
Now create a legacy project:
asdf read the .ruby-version file and switched from Ruby 3.4.6 to 3.2.2 automatically. This compatibility makes adopting asdf easier since you don't need to convert all your projects immediately.
The feature works for Node.js .nvmrc files, Python .python-version files, and other common version files. Check your plugin's documentation to see which legacy formats it supports.
Final thoughts
asdf replaces multiple version managers with a single tool that works consistently across all your runtimes. Install plugins for the tools you need, set versions at global or project level, and let asdf handle the switching automatically. For more details, check the official documentation.