direnv: Per-Directory Environment Loading
direnv reads a .envrc file in the current directory and exports the variables it defines into your shell, unsetting them again when you leave the directory.
direnv keeps project env vars out of your global profile. Its security model (you must explicitly allow each .envrc) is also the thing that trips up CI.
What it does
direnv hooks into your shell prompt. When you cd into a directory containing an .envrc, it evaluates that file and loads the resulting variables; when you leave, it restores the previous environment. Because .envrc is arbitrary shell, direnv refuses to load one until you run direnv allow, which records a trust hash.
Common usage
echo 'export DATABASE_URL=postgres://localhost/dev' > .envrc
direnv allow # trust and load this .envrc
direnv status # show whether it is loaded/allowed
direnv reload # re-evaluate after editing .envrc
# in ~/.bashrc, install the hook once:
eval "$(direnv hook bash)"Options
| Command | What it does |
|---|---|
| direnv allow [path] | Trust the .envrc so it will load |
| direnv deny [path] | Revoke trust for the .envrc |
| direnv hook <shell> | Print the shell hook to eval in your rc file |
| direnv reload | Force a re-evaluation of the current .envrc |
| direnv status | Report loaded/allowed state and config |
| direnv exec <dir> <cmd> | Run a command with that dir’s env loaded |
In CI
CI shells have no interactive prompt, so the hook never fires automatically. Either run direnv allow && eval "$(direnv export bash)" to inject the vars into the current step, or use direnv exec . <command> to wrap a single command with the loaded env. See the export-in-ci reference for the non-interactive pattern.
Common errors in CI
"direnv: error .envrc is blocked. Run direnv allow to approve its content" appears whenever the trust hash is missing, which is always on a fresh checkout; run direnv allow first. "direnv: command not found" means it is not installed (apt-get install -y direnv or brew install direnv). Vars not appearing in later steps is expected: each CI step is a new shell, so re-export per step.