Skip to content

This document is a WORK IN PROGRESS.
This is just a quick personal cheat sheet: treat its contents with caution!


direnv

direnv is an extension for your shell. It augments existing shells with a new feature that can load and unload environment variables depending on the current directory.

Reference(s)

Table of contents


Install

# apt add direnv
# apt install direnv
# dnf install direnv
# emerge -a sys-process/direnv
# nix-env -iA nixos.direnv
# nix-env -iA nixpkgs.direnv
# pacman -S direnv
# yum install direnv
# xbps-install -S direnv
# zypper install direnv

For direnv to work properly it needs to be hooked into the shell. Each shell has its own extension mechanism. Once the hook is configured, restart your shell for direnv to be activated.

Add the following line at the end of $HOME/.bashrc (or ${BDOTDIR:-${HOME/.config/bdotdir}}/.bashrc or wherever):

$ vi $HOME/.bashrc # or ${BDOTDIR:-${HOME/.config/bdotdir}}/.bashrc or wherever
    > ...
    > eval "$(direnv hook bash)"

Make sure it appears even after rvm, git-prompt and other shell extensions that manipulate the prompt.

Add the following line at the end of ${ZDOTDIR:-${HOME}}/.zshrc (or wherever):

$ vi ${ZDOTDIR:-${HOME}}/.zshrc # or wherever
    > ...
    > eval "$(direnv hook zsh)"

Add the following line at the end of $HOME/.config/fish/config.fish (or wherever):

$ vi $HOME/.config/fish/config.fish # or wherever
    > ...
    > direnv hook fish | source

Fish supports 3 modes you can set with the global environment variable direnv_fish_mode:

$ set -g direnv_fish_mode eval_on_arrow    # trigger direnv at prompt, and on every arrow-based directory change (default)
$ set -g direnv_fish_mode eval_after_arrow # trigger direnv at prompt, and only after arrow-based directory changes before executing command
$ set -g direnv_fish_mode disable_arrow    # trigger direnv at prompt only, this is similar functionality to the original behavior

Add the following line at the end of the ~/.cshrc file:

$ vi $HOME/.cshrc # or wherever
    > ...
    > eval `direnv hook tcsh`

Just run:

$> direnv hook elvish > ~/.elvish/lib/direnv.elv
and add the following line to your ~/.elvish/rc.elv file:
$ vi $HOME/.elvish/rc.elv # or wherever
    > ...
    > use direnv


Config

See https://github.com/direnv/direnv/blob/master/man/direnv.toml.1.md.


Use

$ echo "Create a new folder for demo purposes."
$ mkdir ~/my-project
$ cd ~/my-project

$ echo "Show that the FOO environment variable is not loaded."
$ echo ${FOO-nope}
nope

$ echo "Create a new .envrc. This file is bash code that is going to be loaded by direnv."
$ echo export FOO=foo > .envrc
.envrc is not allowed

$ echo "The security mechanism didn't allow to load the .envrc. Since we trust it, let's allow its execution."
$ direnv allow .
direnv: reloading
direnv: loading .envrc
direnv export: +FOO

$ echo "Show that the FOO environment variable is loaded."
$ echo ${FOO-nope}
foo

$ echo "Exit the project."
$ cd ..
direnv: unloading

$ echo "And now FOO is unset again."
$ echo ${FOO-nope}
nope

$ echo "Show how to unset/block direnv (and unset all associated environment variables)."
$ cd my-project
direnv: loading ...
$ echo ${FOO-nope}
foo
$ direnv deny .envrc
direnv: error ~/my-project/.envrc is blocked. Run `direnv allow` to approve its content
$ echo ${FOO-nope}
nope

Before each prompt, direnv checks for the existence of a .envrc or .env file in the current and parent directories. If the file exists (and is authorized), it is loaded into a bash sub-shell and all exported variables are then captured by direnv and then made available to the current shell.

If both .envrc and .env files exists, the .envrc will always be chosen first.

It supports hooks for all the common shells like bash, zsh, tcsh and fish. This allows project-specific environment variables without cluttering the ~/.profile file.

Because direnv is compiled into a single static executable, it is fast enough to be unnoticeable on each prompt. It is also language-agnostic and can be used to build solutions similar to rbenv, pyenv and phpenv.

.envrc also has the advantage of accepting a set of utility functions enhancing the direnv experience, see https://github.com/direnv/direnv/blob/master/man/direnv-stdlib.1.md.


If this cheat sheet has been useful to you, then please consider leaving a star here.