21 Nov 25

Install nix-direnv on wsl

Now that I've got a nix flake for my blog on WSL, I wanted to add direnv and nix-direnv to load the dev shell in my flake whenever I change into the directory where my blog lives. I've used this and similar setups in all the projects I've worked on for the past 5 years at least, and really like it. With it, you just change directory to where your code lives and your developer environment for that project gets loaded for you. Not only that, but after you've loaded the developer environment from your flake, it will cache and reuse it until it changes and needs reevaluating. That keeps the experience nice and snappy.

The way this works is by adding a .envrc file to a directory. If direnv finds this file in a directory you've changed into, and it's got permission to run it (more on this later), then it will run the script to setup your environment. Not only can we use this to load our flake's developer shell, but we can also export environment variables and run other setup scripts required to work on our project.

In addition to having the environment load when you change directory, some editors and IDEs are, or can be made, direnv aware. For example, I used to use VS Code with an extension that loaded my direnv environment whenever the project root had a .envrc file.

Now that I've given you plenty of reasons to use direnv, let's have a look at how to set it up.

Installing direnv

At first I tried installing direnv using my user's nix profile, as I'm used to managing my Linux tools with nix and thought it would be a chance to learn a bit more about my tools. To do this I ran:

nix profile add nixpkgs#direnv

However, once I got to the install step that adds a direnv call to ~/.bashrc I ran into a problem. When .bashrc gets evaluated, my user's nix profile isn't yet loaded, so direnv is nowhere to be found. Rather than play with evaluation order to try and make things work, I just decided to install direnv using the Ubuntu tools.

nix profile remove direnv
sudo apt install direnv

This worked as expected, and direnv was ready to go.

nix-direnv

Out of the box, direnv has some basic nix flake support. However, nix-direnv adds some things that make our lives even better. Firstly, it stops nix from garbage collecting (i.e. deleting) your shell environments until you explicitly choose to clean them up. That means that your environment is cached and loads quickly after the first run. Secondly, some other implementations like lorri require a daemon to run on your system. nix-direnv does not.

A quick apt search nix-direnv shows that nix-direnv isn't available on Ubuntu -- at least with its default package repos. However, we've got a working nix installation, so let's just use that. Things have changed since the last time I installed Nix packages globally without a NixOS configuration. It looks like the new hotness with the nix command is to use nix profile. Per the nix-direnv README we run the following. I'm using add instead of install because install doesn't appear in the help for my nix profile.

nix profile add nixpkgs#nix-direnv

Again, per the instructions, we then make nix-direnv's functionality available to direnv by sourcing some stuff into direnv's rc file. Edit $HOME/.config/direnv/direnvrc and add.

source $HOME/.nix-profile/share/nix-direnv/direnvrc

For completeness, the reason we're doing this system wide and not in our project specific flake is that we need nix-direnv to help us load the flake, so we can't get it from the flake environment.

Loading developer environments

Now we've got our tooling in place, we can tell it to load our developer shell whenever we enter our project's directory. We do this by adding a .envrc file in the directory where we want direnv to load things for us.

Given all we currently need is for direnv to load our developer shell, we just need to add a .envrc file at our project root that contains the following.

use flake

That's it. It's that simple. Nix, direnv, and nix-direnv will take care of the rest by finding our flake and putting its default developer shell into our environment for us. No running nix develop every time we want to work on the project. nix-direnv will also unload the environment when we leave the directory.

A note on security

The one final thing we need to do before direnv will load our .envrc file is to whitelist it. In the directory with the .envrc file, run the following.

direnv allow

We need to run this any time we have a new or modified .envrc file. If direnv didn't require each user to whitelist the file on their machine, then we'd possibly have arbitrary code from the internet running every time we entered a project. For example, if you cloned a project to work on locally and the project contained a .envrc, whatever shell commands were in that file would run as soon as you entered the directory. Not good. So if you ever see direnv asking you to allow a .envrc file that you didn't write, I strongly encourage you to look inside and understand what it's doing before allowing it.