nix-direnv: a persistent use_nix and use_flake for direnv
A fast, persistent use_nix/use_flake implementation for direnv [maintainer=@Mic92 / @bbenne10]
At a glance
- What is it?
- nix-direnv replaces direnv's built-in Nix integration with a cached, garbage-collection-safe version. It is a small shell project for people who already live in Nix shells and want them to load faster after the first run.
- Who is it for?
- Adopt nix-direnv if you already use direnv and Nix and you are tired of re-evaluating a shell on every directory entry; the caching and the gcroots symlink are the whole point. Skip it if you want a daemon that watches files for you, since nix-direnv has none, or if you are on macOS with the system bash 3.2 and are not willing to install direnv through Nix or Homebrew.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 10 days ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What nix-direnv solves, and for whom
direnv already ships a use_nix implementation. The problem nix-direnv addresses is that the built-in one is slow on repeat visits: every time you enter a project directory it can re-run the Nix evaluation and rebuild the shell environment. nix-direnv is described in its README as "a faster, persistent implementation of direnv's use_nix and use_flake, to replace the built-in one." The audience is narrow and specific: developers who already have direnv hooked into their shell and already keep their project dependencies in shell.nix, default.nix or a flake. If you do not use direnv, this project does nothing for you, and the README is explicit that nix-direnv is not a replacement for direnv, only for part of its functionality.
The second stated feature is less obvious but matters just as much in practice. nix-direnv symlinks the resulting shell derivation into the user's gcroots, which prevents garbage collection from deleting build dependencies. The README frames this with a concrete scenario: losing your project's build cache on a flight with no internet connection. That is a real failure mode of plain Nix usage, where a nix-collect-garbage run can quietly remove the store paths your shell depended on. Caching and GC protection are the two things this project sells, and both are about repeated local use rather than first-time setup.
How the caching and the gcroots symlink actually work
The mechanism is visible from the repository layout. The core is a single shell file, direnvrc, which you source from direnv's configuration. It defines the use_nix and use_flake functions that override the built-ins, plus helper functions such as nix_direnv_version, nix_direnv_disallow_fallback and the manual reload switch. There is no daemon and no background process; the README contrasts this directly with lorri, which it says requires an external daemon.
Under the hood, the README states that use_flake calls nix print-dev-env, and that use_nix now does the same, with argument parsing that emulates nix shell for historical reasons. That detail explains the project's main structural limitation: because use_nix parses its arguments by hand, the README admits that only all single-word arguments and some well-known double arguments are interpreted or passed along. Anything more exotic may not reach the underlying command the way you expect. use_flake has a cleaner story here, since all arguments after the flake expression are proxied straight to print-dev-env, which is why the README can suggest invocations like passing --impure.
The persistence layer is the cache plus the gcroots symlink. After the first evaluation, later directory entries reuse the cached environment instead of re-evaluating. The symlink into gcroots is what keeps the store paths alive across garbage collection. Both behaviours are on by default and neither is configurable through a flag in the README; the fine-grained controls that do exist are about fallback and reload timing, not about turning caching off.
Installing nix-direnv and running use flake for the first time
The README lists three requirements before anything else: bash 4.4, nix 2.4 or newer, and direnv 2.21.3 or newer. It also carries a warning that macOS ships bash 3.2 from 2007, and suggests macOS users install direnv through Nix or Homebrew to get a modern bash. Check that first, because nothing below will work on bash 3.2.
The recommended installation path is home-manager. In $HOME/.config/home-manager/home.nix you enable direnv, its bash integration and the nix-direnv module:
{
programs = {
direnv = {
enable = true;
enableBashIntegration = true;
nix-direnv.enable = true;
};
bash.enable = true;
};
}The README notes a trade-off with this method: it is much harder to control which version of nix-direnv you get, so if you need a specific version, use another method. On NixOS 23.05 and later, programs.direnv.enable = true is enough, with the nix-direnv submodule available for finer settings. Without a system configuration, install as a non-root user and source the file from your direnvrc:
nix profile install nixpkgs#nix-direnv
source $HOME/.nix-profile/share/nix-direnv/direnvrcThere is also a source_url variant that pins a version and checksum inside .envrc itself, which is useful when you want the project to carry its own tooling version. Once direnv is installed and hooked into your shell, create a shell.nix in the project:
{ pkgs ? import <nixpkgs> {}}:
pkgs.mkShell {
packages = [ pkgs.hello ];
}Then append the directive to .envrc and allow it. The README gives exactly this pair of commands:
echo "use nix" >> .envrc
direnv allowFor a flake-based project the equivalent is echo "use flake" >> .envrc && direnv allow, and the repository ships a template you can start from with nix flake new -t github:nix-community/nix-direnv <desired output path>. After the first allow, entering the directory should reuse the cached environment rather than rebuild it. If you use a file named something other than shell.nix or default.nix, pass it as an argument, for example use nix foo.nix.
The fallback behaviour and manual reload mode
Two controls deserve attention because they change what happens when things go wrong. The first is the devShell fallback. By default, if nix-direnv discovers that a new version of your shell does not evaluate, it reloads a previously working devShell instead of leaving you with a broken environment. That is a convenience, and it is also a way to keep working against stale dependencies without noticing. You disable it by calling nix_direnv_disallow_fallback in .envrc before the use line:
nix_direnv_disallow_fallback
use nixThe second is manual reload mode, which the README describes as a way to avoid delays and time-consuming rebuilds at unexpected times. In that mode nix-direnv tells you when the environment is no longer up to date and you choose when to reload. The README text is cut off mid-option name in the excerpt available, so the exact activation call is not something I can quote reliably here; check the current README for the precise function name. What is clear from the surrounding text is the intent: move the rebuild from an automatic trigger to a decision you make.
These two settings pull in opposite directions. Fallback protects you from a broken evaluation at the cost of possibly running an old environment. Manual reload protects you from surprise rebuilds at the cost of running an out-of-date environment until you act. Both are reasonable defaults for interactive work, and both are the wrong choice in CI or in a scripted environment where you want a hard failure rather than a silent fallback.
Where nix-direnv is the wrong tool
The clearest limitation is stated by the project itself: use_flake is tested and does work, but the upstream flake API is not finalized, so stability after a nix upgrade cannot be guaranteed. If you are on a rolling channel and you depend on use_flake, a nix upgrade is a real risk to your shell loading, not a hypothetical one. use_nix is the more conservative choice for that reason, at the cost of the argument-parsing limitations described above.
The absence of a daemon is usually presented as a simplification, and it is, but it has a consequence. nix-direnv reacts when direnv evaluates the directory. It does not watch your files in the background and it does not pre-build anything while you are elsewhere in the filesystem. If your workflow depends on the environment being warm before you arrive, this design will not do that for you.
Finally, the bash requirement rules out default macOS setups. The README is direct that the system bash is 3.2 and that you should install direnv via Nix or Homebrew as a workaround. If you cannot or will not change how direnv is installed on that machine, nix-direnv is not usable there regardless of how well it fits the rest of your setup.
nix-direnv versus lorri, and versus plain direnv
The README addresses lorri head-on. Its argument is that nix-direnv is simpler and requires no external daemon, and that lorri can sometimes re-evaluate the entirety of nixpkgs on every change, leading to perpetual high CPU load. That is a design difference, not a feature checklist: lorri runs a background service that watches your files and keeps environments ready, while nix-direnv does its work inside direnv's evaluation and leans on a cache. If you want background pre-building, lorri's model is the one that provides it, and nix-direnv's model deliberately does not.
Against plain direnv the comparison is narrower. direnv already provides use_nix, and nix-direnv is a drop-in replacement for that function plus use_flake. The differences are the caching after the first run and the gcroots symlink that protects build dependencies from garbage collection. If neither of those matters to you, plain direnv is fewer moving parts. If you have ever run nix-collect-garbage and then found your shell rebuilding from scratch, the gcroots behaviour is the reason to switch.
The search interest around devenv suggests a third comparison, but the README does not describe devenv, so I will not pretend to draw one. What can be said is that nix-direnv is deliberately small: one shell file, a template, and tests. It integrates with whatever Nix expression you already have rather than defining its own project model.
Maintenance, licensing and upgrade cost
The repository is not archived, and the last push was on 2026-09-20. The most recent release listed is 3.2.0 from 2026-07-28, with 3.1.2 on the same day and 3.1.1 earlier in 2026. That is a maintained project with a recent release and recent commits, though the release cadence is not dense. The topics list includes managed-by-renovate, which is consistent with dependency updates arriving through automation rather than hand-edited pins.
The upgrade cost depends on how you installed it. Through home-manager or a NixOS system configuration, the version moves with your system generation, and the README warns that this method makes version control harder. Through the source_url method, the version is pinned in your .envrc with a checksum, so upgrading means editing the version string and the hash, and the README's own example shows the nix_direnv_version guard that lets you require a minimum version before sourcing. That guard is the cheapest upgrade protection available here: if a machine has an older nix-direnv, the guard fails loudly instead of running against an unexpected version.
The licence is MIT, which is permissive and places few obligations on how you redistribute or embed the direnvrc file. I am not a lawyer and this is not legal advice; if you vendor the file into a product, read the LICENSE text in the repository yourself.
Editorial conclusion
Adopt nix-direnv if you already use direnv and Nix and you are tired of re-evaluating a shell on every directory entry; the caching and the gcroots symlink are the whole point. Skip it if you want a daemon that watches files for you, since nix-direnv has none, or if you are on macOS with the system bash 3.2 and are not willing to install direnv through Nix or Homebrew. Before committing, check your bash version, your nix and direnv versions against the stated minimums, and decide whether you want the default fallback behaviour or want to call nix_direnv_disallow_fallback in your .envrc.
Frequently asked questions
How do I install nix-direnv?
The README recommends home-manager, where you set programs.direnv.enable, enableBashIntegration and nix-direnv.enable in home.nix. Alternatives are the NixOS programs.direnv.enable option, nix profile install nixpkgs#nix-direnv followed by sourcing the direnvrc, or the source_url method inside .envrc.
How do I use nix direnv in a project?
Add a shell.nix or default.nix to the project, then append use nix to .envrc and run direnv allow. For flakes, append use flake to .envrc and run direnv allow instead.
What is nix-direnv?
It is a faster, persistent implementation of direnv's use_nix and use_flake, meant to replace the built-in ones. It caches the nix-shell environment after the first run and symlinks the resulting shell derivation in the user's gcroots so garbage collection does not remove build dependencies.
What is the difference between nix-direnv and lorri?
The README says nix-direnv is simpler and requires no external daemon, while lorri can sometimes re-evaluate the entirety of nixpkgs on every change, leading to perpetual high CPU load. lorri runs a background daemon; nix-direnv does not.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nix-community-nix-direnv)