Using direnv with Nix and Emacs

A mess From Pexels cottonbro

Using direnv with Nix and Emacs

I wanted my Emacs to automatically pick up the Nix environment for each project, so I set up direnv to manage project-specific shells. I was finding it a pain cd into a project, running nix-shell and then starting emacs.

1. Install direnv

Let’s be completely honest here. I can’t quite remember whether sudo apt-get install direnv was important, or whether I installed it direnv using Nix. I think, after a lot of fighting, the important thing was that I have a binary (linked) file direnv in my .nix-profile/bin folder. So I don’t think I need the system (apt-get install) file.

nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs
nix-channel --update
nix-env -iA nixpkgs.direnv

Basically, I got in a lot of trouble doing this, got very confused and don’t fully understand what I was doing. I think one of my problems might have been that direnv wasn’t in my rix archive (because of course, I’m trying to use rix). I had to upgrade my nix installation before I got any of this to work as well; something I need to take more care of going forward. I do sudo apt-get update and sudo apt-get upgrade often enough but nixitself is outside that system. Because I was looking for nix-direnv (which doesn’t exist) it may be that I can get the package from rix. After some confusing investigations, I didn’t use nix-direnv; the official direnv package contains everything needed (in particular the binaries). I don’t know if I need a system-wide direnv which looks for a specific direnv.

I added the following to ~/.bashrc so that every time I cd into a folder, direnv automatically loads the environment:

Inside my project folder, I created a .envrc file:

use nix

Then I ran

direnv allow

Making it work in Emacs

I wanted Emacs to pick up the same Nix environment. Here’s how I set it up.

sing use-package in my .emacs:

(use-package direnv
  :ensure t
  :config
  (direnv-mode))  ;; automatically enable direnv-mode

To make sure emacs can see the shell environment (I usually initialise from the Gui).

(use-package exec-path-from-shell
  :ensure t
  :config
  (exec-path-from-shell-initialize))

Sometimes I needed to run

M-x direnv-update-environment

but I haven’t run that for a while.

Notes

  • .envrc can be several folders upstream; direnv still finds it automatically.
  • Once direnv allow is run, both terminal shells and Emacs buffers inherit the environment.
  • I didn’t need a ~/.direnvrc file. All the setup works with just the project .envrc and shell hook, that was a rabbit hole I mention now in case I left a few .direnvrcfiles lying around and wonder if they are important one day.

With this configuration, I now have a seamless workflow: I can open files anywhere in the project, and Emacs automatically uses the correct Nix environment.