Nix and direnv - a match made in heaven
This is just a quick post to praise the combination of Nix and direnv.
Here's how my current setup looks (using the tofu program as an example, it
works for any program available in
nixpkgs):
❯ tofu version
tofu: command not found
❯ cd ~/Documents/homelab
❯ tofu version
OpenTofu v1.7.1
on linux_amd64
Did you notice? I didn't have to do anything to get the correct version of
tofu in my shell. I just cd into the project, and it's there.
Okay, I lied a little. I did have to do something to get this to work. I have a
flake.nix file in my project directory that defines all dependencies for the
project. Almost all of my projects now have a flake.nix file, and it looks
something like this:
# Truncated for brevity
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
};
outputs = { self, nixpkgs }:
# ...
{
devShells.default = mkShell {
packages = [
# The list of dependencies for this project
kubectl
opentofu
go
# ...
];
};
}
);
}
And in my .envrc file:
use flake
You can think of this as a Cargo.toml or package.json file, but for all CLI
tools.
This is the magic of nix and direnv:
- All dependencies are managed by a per-project
flake.nixfile. - No need to worry about different versions of dependencies for different projects.
- Extremely fast thanks to
nix-direnvinstead of the defaultdirenvimplementation. - Works without containers or abstractions - just a
$PATHmanager on steroids!
To set them up, assuming you're using NixOS:
{
programs = {
direnv = {
enable = true;
silent = true;
};
};
}
NixOS already uses nix-direnv by default, so you don't have to enable it
explicitly.