# nix-direnv ![Test](https://github.com/nix-community/nix-direnv/workflows/Test/badge.svg) 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-shell` environment - 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](https://github.com/nix-community/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`/`grep` via Nix or Homebrew. > Discussion of these problems can be found > [here](https://github.com/nix-community/nix-direnv/issues/3). 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 ```Nix { 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`: ```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`: ```Nix keep-derivations = true keep-outputs = true ```
Direnv's source_url ### Direnv source_url Put the following lines in your `.envrc`: ```bash if ! has nix_direnv_version || ! nix_direnv_version 2.2.0; then source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.0/direnvrc" "sha256-5EwyKnkJNQeXrRkYbwwRBcXbibosCJqyIUuz9Xq+LRc=" fi ```
Via configuration.nix in NixOS ### Via configuration.nix in NixOS In `/etc/nixos/configuration.nix`: ```Nix { pkgs, ... }: { environment.systemPackages = with pkgs; [ direnv nix-direnv ]; # nix options for derivations to persist garbage collection nix.extraOptions = '' 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` ```bash # 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: ```shell nix-env -f '' -iA nix-direnv ``` Then add nix-direnv to `$HOME/.direnvrc`: ```bash 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`: ```bash # 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: ``` nix # save this as shell.nix { pkgs ? import {}}: pkgs.mkShell { nativeBuildInputs = [ pkgs.hello ]; } ``` Then add the line `use nix` to your envrc: ```console $ echo "use nix" >> .envrc $ direnv allow ``` If you haven't used direnv before, make sure to [hook it into your shell](https://direnv.net/docs/hook.html) 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.: ```console $ 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](https://github.com/nix-community/nix-direnv/tree/master/templates/flake). which provides a basic flake with devShell integration and a basic `.envrc`. To make use of this template, you may issue the following command: ```console $ nix flake new -t github:nix-community/nix-direnv ``` ### Integrating with a existing flake ```console $ 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: ```bash 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: ```console $ 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 nix` this is: * `~/.direnvrc` * `~/.config/direnv/direnvrc` * `.envrc`, * A single nix file. In order of preference: + The file argument to `use nix` + `default.nix` if it exists + `shell.nix` if it exists - for `use flake` this is: * `~/.direnvrc` * `~/.config/direnv/direnvrc` * `.envrc` * `flake.nix` * `flake.lock` * `devshell.toml` if it exists To add more files to be checked use `nix_direnv_watch_file` like this ```shell 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: ```shell 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. ## General direnv tips - [Changing where direnv stores its cache](https://github.com/direnv/direnv/wiki/Customizing-cache-location) - [Quickly setting up direnv in a new nix project](https://github.com/nix-community/nix-direnv/wiki/Shell-integration) ## Other projects in the field - [lorri](https://github.com/nix-community/lorri) - [sorri](https://github.com/nmattia/sorri) - [nixify](https://github.com/kalbasit/nur-packages/blob/master/pkgs/nixify/envrc) - [lorelei](https://github.com/shajra/direnv-nix-lorelei)