Oct 26, 2022

asdf and direnv - isolated environment heaven

Well, maybe not quite heaven, but the combination of asdf and direnv is the best solution I've found to the problem of:

  1. Managing multiple versions of languages installed at the same time

  2. Creating isolated environments for application development with a specific language version

Of course lots of people prefer Docker or Nix to achieve this.

For me, on an Apple Silicon macBook, with the languages and tools I use, I've found asdf and direnv to be effective without too much complexity.

(This guide assumes you're on macOS - if not, most of it will be the same except for the 'brew install' parts - please substitute your OS package manager install commands.)

asdf intro and install

asdf is a tool version manager. Please read the asdf introdcuction page to get an overview.

To install asdf:

brew install asdf
echo -e "\n. $(brew --prefix asdf)/libexec/asdf.sh" >> ${ZDOTDIR:-~}/.zshrc


direnv is an extension for your shell. It augments existing shells with a new feature that can load and unload environment variables depending on the current directory. We're going to use asdf to install direnv and configure for our shell:

asdf plugin-add direnv
asdf install direnv latest
asdf global direnv latest
asdf direnv setup --shell zsh --version latest
exec $SHELL
which direnv

Now we can test if direnv is working by creating a test directory and loading some environment varables:

mkdir test && cd test
echo export FOO=foo > .envrc
direnv allow
echo $FOO
cd ..
cd test

direnv can optionally also load .env files as well as .envrc files. This can be useful if you use 'dotenv' which is a popular way of programmatially loading environment variables in languages such as JavaScript, Python and Ruby. Add this to any .envrc file:


Installing a language version with asdf

For our example we'll install a version of nodeJS - you can also follow asdf docs for other languages such as Ruby and Python.

asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git
asdf install nodejs 18.12.0

Now we can set up a direcory to be an isolated environment with the language version we want:

asdf direnv local nodejs 18.12.0

This creates a .tool-versions file and updates .envrc. Now whenever we cd into our directory we ge the environment we need.

We can test out the isolated environment by installing some dependencies:

npm install smallest

This should create a local package.json and node_modules directory, all using the language version specified in tool-versions.

Installing other language runtimes

asdf has official plugins for Ruby, nodejs, Elixir and Erlang. It has a solid community plugin for Python.

I've had good success installing Python, Ruby, Erlang and Elixir using this method on an Applie Silicon (M1) mac. PHP has been less successful due to challenges installing on this processor architecture. So if you can live with running the latest version of PHP then just do a brew install phpand move on.

Bonus points for direnv

direnv has a feature called layouts that can be useful for improving your experience with some languages. I've found this especially useful with Ruby and Python. Here's a blog post with a good example of using a layout for Python.

direnv has a command called PATH_add which can be useful for changing the path within a directory structure. e.g. I've used this to avoid globally installing an npm module: PATHadd ./nodemodules/ghost-cli/bin


Tom Atkins’ website. You might also like my shared links, photos and short posts on Bluesky. Email [email protected]

Powered by PostOwl. Page viewed … times.