9 KiB
nix-direnv
A faster, persistent implementation of direnv's use_nix and use_flake,
to replace the built-in one.
Prominent features:
- significantly faster after the first run by caching the
nix-shellenvironment - prevents garbage collection of build dependencies by symlinking the resulting
shell derivation in the user's
gcroots(Life is too short to lose your project's build cache if you are on a flight with no internet connection)
Why not use lorri instead?
Compared to lorri, nix-direnv is simpler (and requires no external daemon) and supports flakes. Additionally, lorri can sometimes re-evaluate the entirety of nixpkgs on every change (leading to perpetual high CPU load).
Installation
Heads up: nix-direnv requires a modern Bash and GNU Grep. MacOS ships with outdated or non-GNU versions of these tools, As a work-around we suggest that macOS users install
direnv/grepvia Nix or Homebrew. Discussion of these problems can be found here.
There are different ways to install nix-direnv, pick your favourite:
Via home-manager (Recommended)
Via home-manager
Note that while the home-manager integration is recommended, some use cases require the use of features only present in some versions of nix-direnv. It is much harder to control the version of nix-direnv installedwith this method. If you require such specific control, please use another method of installing nix-direnv.
In $HOME/.config/nixpkgs/home.nix add
{ pkgs, ... }:
{
# ...other config, other config...
programs.direnv.enable = true;
programs.direnv.nix-direnv.enable = true;
# optional for nix flakes support in home-manager 21.11, not required in home-manager unstable or 22.05
programs.direnv.nix-direnv.enableFlakes = true;
programs.bash.enable = true;
# OR
programs.zsh.enable = true;
# Or any other shell you're using.
}
Optional: To protect your nix-shell against garbage collection you also need to add these options to your Nix configuration.
If you are on NixOS also add the following lines to your /etc/nixos/configuration.nix:
{ pkgs, ... }: {
nix.extraOptions = ''
keep-outputs = true
keep-derivations = true
'';
}
On other systems with Nix add the following configuration to your /etc/nix/nix.conf:
keep-derivations = true
keep-outputs = true
Direnv's source_url
Direnv source_url
Put the following lines in your .envrc:
if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-5EwyKnkJNQeXrRkYbwwRBcXbibosCJqyIUuz9Xq+LRc="
fi
Via configuration.nix in NixOS
Via configuration.nix in NixOS
In /etc/nixos/configuration.nix:
{ pkgs, ... }: {
environment.systemPackages = with pkgs; [ direnv nix-direnv ];
# nix options for derivations to persist garbage collection
nix.settings = {
keep-outputs = true;
keep-derivations = true;
};
environment.pathsToLink = [
"/share/nix-direnv"
];
# if you also want support for flakes
nixpkgs.overlays = [
(self: super: { nix-direnv = super.nix-direnv.override { enableFlakes = true; }; } )
];
}
Then source the direnvrc from this repository in your own $HOME/.direnvrc
# put this in ~/.direnvrc
source /run/current-system/sw/share/nix-direnv/direnvrc
With nix-env
With nix-env
As non-root user do the following:
nix-env -f '<nixpkgs>' -iA nix-direnv
Then add nix-direnv to $HOME/.direnvrc:
source $HOME/.nix-profile/share/nix-direnv/direnvrc
You also need to set keep-outputs and keep-derivations to nix.conf
as described in the installation via home-manager section.
From source
From source
Clone the repository to some directory
and then source the direnvrc from this repository in your own ~/.direnvrc
or ~/.config/direnv/direnvrc:
# put this in ~/.direnvrc or ~/.config/direnv/direnvrc
source $HOME/nix-direnv/direnvrc
You also need to set keep-outputs and keep-derivations to nix.conf
as described in the installation via home-manager section.
Usage example
Either add shell.nix or a default.nix to the project directory:
# save this as shell.nix
{ pkgs ? import <nixpkgs> {}}:
pkgs.mkShell {
packages = [ pkgs.hello ];
}
Then add the line use nix to your envrc:
$ echo "use nix" >> .envrc
$ direnv allow
If you haven't used direnv before, make sure to hook it into your shell first.
Using a non-standard file name
You may use a different file name than shell.nix or default.nix
by passing the file name in .envrc, e.g.:
$ echo "use nix foo.nix" >> .envrc
Flakes support
nix-direnv also comes with an alternative use_flake implementation.
The code is tested and does work but the upstream flake api is not finalized,
so we we cannot guarantee stability after an nix upgrade.
Like use_nix,
our use_flake will prevent garbage collection of downloaded packages,
including flake inputs.
Creating a new flake-native project
This repository ships with a flake template.
which provides a basic flake with devShell integration and a basic .envrc.
To make use of this template, you may issue the following command:
$ nix flake new -t github:nix-community/nix-direnv <desired output path>
Integrating with a existing flake
$ echo "use flake" >> .envrc && direnv allow
The use flake line also takes an additional arbitrary flake parameter,
so you can point at external flakes as follows:
use flake ~/myflakes#project
Advanced usage
use flake
Under the covers, use_flake calls nix print-dev-env.
The first argument to the use_flake function is the flake expression to use,
and all other arguments are proxied along to the call to print-dev-env.
You may make use of this fact for some more arcane invocations.
For instance, if you have a flake that needs to be called impurely under some conditions,
you may wish to pass --impure to the print-dev-env invocation
so that the environment of the calling shell is passed in.
You can do that as follows:
$ echo "use flake . --impure" > .envrc
$ direnv allow
use nix
Like use flake, use nix now uses nix print-dev-env.
Due to historical reasons, the argument parsing emulates nix shell.
This leads to some limitations in what we can reasonably parse.
Currently, all single-word arguments and some well-known double arguments will be interpeted or passed along.
Known arguments
-p: Starts a list of packages to install; consumes all remaining arguments--include/-I: Add the following path to the list of lookup locations for<...>file names--attr/-A: Specify the output attribute to utilize
--command, --run, --exclude, --pure, -i, and --keep are explicitly ignored.
All single word arguments (-j4, --impure etc)
are passed to the underlying nix invocation.
Tracked files
nix-direnv makes a performance tradeoff
and only considers changes in a limited number of files
when deciding to update its cache.
-
for
use nixthis is:~/.direnvrc~/.config/direnv/direnvrc.envrc,- A single nix file. In order of preference:
- The file argument to
use nix default.nixif it existsshell.nixif it exists
- The file argument to
-
for
use flakethis is:~/.direnvrc~/.config/direnv/direnvrc.envrcflake.nixflake.lockdevshell.tomlif it exists
To add more files to be checked use nix_direnv_watch_file like this
nix_direnv_watch_file your-file.nix
use nix # or use flake
Or - if you don't mind the overhead (runtime and conceptual) of watching all nix-files:
nix_direnv_watch_file $(find . -name "*.nix" -printf '"%p" ')
Note that this will re-execute direnv for any nix change, regardless of whether that change is meaningful for the devShell in use.
nix_direnv_watch_file must be invoked before either use flake or use nix to take effect.