nix-direnv
A fast, persistent use_nix/use_flake implementation for direnv [maintainer=@Mic92 / @bbenne10]
Top Related Projects
Quick Overview
nix-direnv is a fast and efficient integration of Nix and direnv. It allows for automatic loading of Nix environments when entering a directory, providing seamless development environment management. This project enhances the developer experience by combining the power of Nix's reproducible builds with direnv's automatic environment switching.
Pros
- Fast and efficient loading of Nix environments
- Seamless integration with existing direnv workflows
- Supports caching of Nix environments for improved performance
- Compatible with various Nix-based development tools and frameworks
Cons
- Requires both Nix and direnv to be installed and configured
- May have a learning curve for users unfamiliar with Nix or direnv
- Limited to Nix-based environments, not suitable for non-Nix projects
- Potential for increased disk usage due to cached environments
Getting Started
- Install Nix and direnv on your system.
- Install nix-direnv:
nix-env -f '<nixpkgs>' -iA nix-direnv
- Add the following to your
~/.config/direnv/direnvrc
or~/.direnvrc
:source $HOME/.nix-profile/share/nix-direnv/direnvrc
- Create a
.envrc
file in your project directory:echo "use nix" > .envrc
- Allow direnv to load the environment:
direnv allow
Now, whenever you enter the directory, nix-direnv will automatically load the Nix environment defined in your shell.nix
or default.nix
file.
Competitor Comparisons
unclutter your .profile
Pros of direnv
- Language-agnostic and works with various development environments
- Lightweight and fast, with minimal dependencies
- Supports a wide range of shell environments (bash, zsh, fish, etc.)
Cons of direnv
- Requires manual setup of environment variables for each project
- Lacks built-in integration with Nix ecosystem
- May require additional tools for more complex environment management
Code Comparison
direnv (.envrc file):
export PROJECT_ROOT=$(pwd)
export PATH=$PROJECT_ROOT/bin:$PATH
export DATABASE_URL="postgresql://user:password@localhost/mydb"
nix-direnv (shell.nix file):
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [ pkgs.postgresql pkgs.nodejs ];
shellHook = ''
export DATABASE_URL="postgresql://user:password@localhost/mydb"
'';
}
Summary
direnv is a versatile, language-agnostic tool for managing project-specific environment variables. It's lightweight and supports various shells, but requires manual setup for each project. nix-direnv, on the other hand, leverages the Nix ecosystem for more comprehensive environment management, including package dependencies, but is specific to Nix-based workflows.
Fast, Declarative, Reproducible, and Composable Developer Environments
Pros of devenv
- Offers a more comprehensive development environment setup, including services and processes
- Provides a higher-level abstraction for development environment configuration
- Includes built-in support for various languages and tools out of the box
Cons of devenv
- May have a steeper learning curve for users new to Nix
- Potentially more complex setup for simple projects
- Less flexible for projects with very specific or unusual requirements
Code Comparison
nix-direnv:
use_nix() {
local path="$(nix-instantiate --find-file nixpkgs)"
local drv="$(nix-instantiate --expr "(import $path {}).mkShell {}")"
nix-shell "$drv" "$@"
}
devenv:
{ pkgs, ... }:
{
packages = [ pkgs.hello ];
languages.python.enable = true;
services.postgres.enable = true;
}
The nix-direnv example shows a simple function to create a Nix shell, while the devenv example demonstrates a more declarative approach to defining a development environment with built-in language and service support.
Per project developer environments
Pros of devshell
- More flexible and customizable environment setup
- Supports multiple shells and configurations
- Easier integration with existing Nix projects
Cons of devshell
- Steeper learning curve for newcomers to Nix
- Requires more manual configuration
- Less seamless integration with direnv
Code Comparison
nix-direnv:
use_nix() {
local path="$(nix-instantiate --find-file nixpkgs)"
if [ -f "${path}/.version-suffix" ]; then
local version="$(< $path/.version-suffix)"
elif [ -f "${path}/.git" ]; then
local version="$(cd $path && git describe --always --dirty)"
fi
local cache=".direnv/cache-${version:-unknown}"
if [[ ! -e "$cache" ]] || \
[[ "$HOME/.direnvrc" -nt "$cache" ]] || \
[[ .envrc -nt "$cache" ]] || \
[[ default.nix -nt "$cache" ]] || \
[[ shell.nix -nt "$cache" ]];
then
local tmp="$(nix-shell --show-trace --pure "$@" \
--run "\"$direnv\" dump bash")";
echo "$tmp" > "$cache"
fi
direnv_load cat "$cache"
watch_file default.nix
watch_file shell.nix
}
devshell:
{ pkgs ? import <nixpkgs> { } }:
pkgs.devshell.mkShell {
imports = [ (pkgs.devshell.importTOML ./devshell.toml) ];
packages = [ pkgs.hello ];
commands = [
{
name = "hello";
help = "Print hello world";
command = "hello";
}
];
}
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
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-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, 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. MacOS ships with bash 3.2 from 2007. As a work-around we suggest that macOS users install
direnv
via Nix or Homebrew. 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 installed with this method. If you require such specific control, please use another method of installing nix-direnv.
In $HOME/.config/home-manager/home.nix
add
{
# ...other config, other config...
programs = {
direnv = {
enable = true;
enableBashIntegration = true; # see note on other shells below
nix-direnv.enable = true;
};
bash.enable = true; # see note on other shells below
};
}
Check the current
Home Manager Options
for integration with shells other than Bash. Be sure to also allow
home-manager
to manage your shell with programs.<your_shell>.enable = true
.
Direnv's source_url
Direnv source_url
Put the following lines in your .envrc
:
if ! has nix_direnv_version || ! nix_direnv_version 3.0.6; then
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.6/direnvrc" "sha256-RYcUJaRMf8oF5LznDrlCXbkOQrywm0HDv1VjYGaJGdM="
fi
Via system configuration on NixOS
Via system configuration on NixOS
For NixOS 23.05+ all that's required is
{
programs.direnv.enable = true;
}
other available options are:
{ pkgs, ... }: {
#set to default values
programs.direnv = {
package = pkgs.direnv;
silent = false;
loadInNixShell = true;
direnvrcExtra = "";
nix-direnv = {
enable = true;
package = pkgs.nix-direnv;
};
}
With `nix profile`
With nix profile
As non-root user do the following:
nix profile install nixpkgs#nix-direnv
Then add nix-direnv to $HOME/.config/direnv/direnvrc
:
source $HOME/.nix-profile/share/nix-direnv/direnvrc
From source
From source
Clone the repository to some directory and then source the direnvrc from this
repository in your own ~/.config/direnv/direnvrc
:
# put this in ~/.config/direnv/direnvrc
source $HOME/nix-direnv/direnvrc
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
cannot guarantee stability after a 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 interpreted or passed along.
Manual reload of the nix environment
To avoid delays and time consuming rebuilds at unexpected times, you can use nix-direnv in the "manual reload" mode. nix-direnv will then tell you when the nix environment is no longer up to date. You can then decide yourself when you want to reload the nix environment.
To activate manual mode, use nix_direnv_manual_reload
in your .envrc
like
this:
nix_direnv_manual_reload
use nix # or use flake
To reload your nix environment, use the nix-direnv-reload
command:
$ nix-direnv-reload
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
As a convenience, nix-direnv
adds common files to direnv's watched file list
automatically.
The list of additionally tracked files is as follows:
-
for
use nix
:~/.direnvrc
~/.config/direnv/direnvrc
.envrc
,- A single nix file. In order of preference:
- The file argument to
use nix
default.nix
if it existsshell.nix
if it exists
- The file argument to
-
for
use flake
:~/.direnvrc
~/.config/direnv/direnvrc
.envrc
flake.nix
flake.lock
devshell.toml
if it exists
Users are free to use direnv's builtin watch_file
function to track additional
files. watch_file
must be invoked before either use flake
or use nix
to
take effect.
Environment Variables
nix-direnv sets the following environment variables for user consumption. All other environment variables are either a product of the underlying nix invocation or are purely incidental and should not be relied upon.
NIX_DIRENV_DID_FALLBACK
: Set when the current revision of your nix shell or flake's devShell are invalid and nix-direnv has loaded the last known working shell.
nix-direnv also respects the following environment variables for configuration.
NIX_DIRENV_FALLBACK_NIX
: Can be set to a fallback Nix binary location, to be used when a compatible one isn't available inPATH
. Defaults toconfig.nix.package
if installed via the NixOS module, otherwise needs to be set manually. Leave unset or empty to fail immediately when a Nix implementation can't be found onPATH
.
General direnv tips
- Changing where direnv stores its cache
- Quickly setting up direnv in a new nix project
- Disable the diff notice (requires direnv 2.34+): Note that this goes into direnv's TOML configuration!
Other projects in the field
Top Related Projects
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot