Adhoc development environments with Nix
I've recently started exploring Python and Haskell. When working with projects in these, I need to have a bunch of dependencies installed. For example, with Python, I'd need a version of the Python interpreter itself, Pip of Pipenv or something similar for installing external modules, maybe a language server like pyright etc.
But I don't need these installed and available all the time, polluting my $PATH
That's where Nix comes in.
Nix has a way to define development shells and activate them only when needed. When activated, it will update variables like $PATH
and make any extra dependencies available. Once done working on something, it can be deactivated.
For example, below is a simple dev shell which installs go 1.20
.
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
};
outputs = { self, nixpkgs, }:
let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
};
in
{
devShells.${system}.default = pkgs.mkShell {
packages = [
pkgs.go_1_20
];
};
};
}
After creating a file called flake.nix
in the project directory, it can be activated with the nix develop
command. And once done, the shell can be closed with exit
or Ctrl+d.
The problem with this is that, it starts a new bash
shell with a really generic prompt. So any customizations made in .bashrc
or .zshrc
etc. gets lost.
Direnv to the rescue
Direnv is a tool that, once hooked up with the shell, will execute a set of commands mentioned in a per project .envrc
file. It will execute these commands automatically when cd'd into the directory and the changes will be reverted when cd'ing out.
Direnv has something they call the stdlib
, which is a set of sane defaults in the form of functions that can be put into the envrc
. One such function is the use_flake
function.
By creating a file called .envrc
in the project directory with the content
use_flake
direnv will automatically append the environment created by the devShell defined in flake.nix to the existing shell env, without starting a new shell or losing any of the customizations from .bashrc
or .zshrc