Have you ever used a tool like pip
's bin/activate
script, or rbenv
? These
tools populate your shell environment with the right tools and scripts and
dependencies (e.g. PYTHONPATH
) to run your software.
What if I told you there was a magical tool that worked like that, and could do it for arbitrary languages and tools?
That tool is called direnv.
First, install direnv
:
$ nix profile install nixpkgs#direnv
$ which direnv
/home/austin/.nix-profile/bin/direnv
Now, you need to activate it in your shell by hooking into it. If you're using
Bash, try putting this in your .bashrc
and starting up a new interactive
shell:
eval "$(direnv hook bash)"
Not using bash? Check the direnv hook documentation for more.
Let's go back to the nix-postgres
source code.
cd $HOME/tmp-nix-postgres
Now, normally, direnv is going to look for a file called .envrc
and load that
if it exists. But to be polite, we don't do that by default; we keep a file
named .envrc.recommended
in the repository instead, and encourage people to do
this:
echo "source_env .envrc.recommended" >> .envrc
All this says is "Load the code from .envrc.recommended
directly", just like a
normal bash script using source
. The idea of this pattern is to allow users to
have their own customized .envrc
and piggyback on the committed code for
utility — and .envrc
is .gitignore
'd, so you can put e.g. secret
tokens inside without fear of committing them.
Run the above command, and then...
Oops, a big red error appeared?
$ echo "source_env .envrc.recommended" >> .envrc
direnv: error /home/austin/work/nix-postgres/.envrc is blocked. Run `direnv allow` to approve its content
What happened? By default, as a security measure, direnv
does not load or
execute any code from an .envrc
file, and instead it MUST be allowed
explicitly.
Our .envrc.recommended
file will integrate with Nix directly. So run
direnv allow
, and you'll suddenly see the following:
$ direnv allow
direnv: loading ~/work/nix-postgres/.envrc
direnv: loading ~/work/nix-postgres/.envrc.recommended
direnv: loading https://raw.githubusercontent.com/nix-community/nix-direnv/2.3.0/direnvrc (sha256-Dmd+j63L84wuzgyjITIfSxSD57Tx7v51DMxVZOsiUD8=)
direnv: using flake
direnv: nix-direnv: renewed cache
direnv: export +AR +AS +CC +CONFIG_SHELL +CXX +DETERMINISTIC_BUILD +HOST_PATH +IN_NIX_SHELL +LD +NIX_BINTOOLS +NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_BUILD_CORES +NIX_CC +NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_CFLAGS_COMPILE +NIX_ENFORCE_NO_NATIVE +NIX_HARDENING_ENABLE +NIX_LDFLAGS +NIX_STORE +NM +OBJCOPY +OBJDUMP +PYTHONHASHSEED +PYTHONNOUSERSITE +PYTHONPATH +RANLIB +READELF +SIZE +SOURCE_DATE_EPOCH +STRINGS +STRIP +_PYTHON_HOST_PLATFORM +_PYTHON_SYSCONFIGDATA_NAME +__structuredAttrs +buildInputs +buildPhase +builder +cmakeFlags +configureFlags +depsBuildBuild +depsBuildBuildPropagated +depsBuildTarget +depsBuildTargetPropagated +depsHostHost +depsHostHostPropagated +depsTargetTarget +depsTargetTargetPropagated +doCheck +doInstallCheck +dontAddDisableDepTrack +mesonFlags +name +nativeBuildInputs +out +outputs +patches +phases +preferLocalBuild +propagatedBuildInputs +propagatedNativeBuildInputs +shell +shellHook +stdenv +strictDeps +system ~PATH ~XDG_DATA_DIRS
What just happened is that we populated the ambient shell environment with tools
specified inside of flake.nix
— we'll cover Flakes later. But for now,
your tools are provisioned!
Previously, we needed to run nix develop
to get access to the just
command.
No longer! It's now available in your shell:
$ which just
/nix/store/1di6nb4qsv86907l3xarw4llzdss2g89-just-1.14.0/bin/just
$ just b
...
Viola, done!
When you cd ~
, direnv will automatically unload the .envrc
file for you:
$ cd ~
direnv: unloading
Now, just
is no longer available:
$ just build-all
just: command not found
And if you go back, it is!
$ cd $HOME/nix-postgres
direnv: loading ~/work/nix-postgres/.envrc
direnv: loading ~/work/nix-postgres/.envrc.recommended
direnv: loading https://raw.githubusercontent.com/nix-community/nix-direnv/2.3.0/direnvrc (sha256-Dmd+j63L84wuzgyjITIfSxSD57Tx7v51DMxVZOsiUD8=)
direnv: using flake
...
$ just build-all
...
direnv
with Nix is a frighteningly good development combination for many
purposes. This is its main power: you can use it to create on-demand developer
shells for any language, tool, or environment, and all you need to do is cd
to
the right directory.
This is the power of direnv
: your projects always, on demand, will have the
right tools configured and available, no matter if you last worked on them a day
ago or a year ago, or it was done by your teammate, or you have a brand new
computer that you've never programmed on.