Two direnv extensions which help ensure a project's environment variables are properly set up
Why direnv?
I prefer to use direnv in development rather than .env
files because direnv provides configuration via the environment itself, rather than via a system that has to be explicitly loaded. The application knows nothing about how its environment is set up.
My Requirements
I want any project I create to have a template for setting up development environment and checks that things stay aligned.
First, I add a note to every project's README to indicate that direnv is required in development.
Any developer who works a project configured this way will need to set it up.
Once they've got that working, the developer (who may be myself months later!) needs to know what values to set and what they mean.
I achieve this by through the combination of .envrc
and .envrc.private
and the use of two direnv functions that check that everything's been set up correctly.
.envrc
All my projects have an .envrc
file which is included in the repo and which look like this:
# SOME_REQUIRED_VARIABLE: some variable that must be set for the application to run
export SOME_REQUIRED_VARIABLE=
# SOME_OTHER_VAR: (optional) a variable you don't necessarily need to set
export SOME_OTHER_VAR=
# A_VARIABLE_WITH_A_DEFAULT: true*|false - a variable that has a default
export A_VARIABLE_WITH_A_DEFAULT=true
source_env .envrc.private
if has ensure_all_documented; then
ensure_all_documented
else
echo "No ensure_all_documented function found, skipping documentation check. Install from here: https://raw.githubusercontent.com/joeyates/dotfiles/refs/heads/main/.config/direnv/direnvrc"
fi
if has ensure_all_set; then
ensure_all_set
else
echo "No ensure_all_set function found, skipping environment variable check. Install from here: https://raw.githubusercontent.com/joeyates/dotfiles/refs/heads/main/.config/direnv/direnvrc"
fi
All the environment variables that the application relies on to be set are included, possibily with default values. Each variable has documentation, which can also indicate if the variable is optional
.
The Checks
The two functions, ensure_all_documented
and ensure_all_set
are available from my dotfiles repo.
Note that nothing breaks if you don't have them, you just get a nagging message every time you run direnv allow
to update things.
ensure_all_set
checks that all the environment variables set in .envrc
have been given a value.
ensure_all_set
is an automatic version of direnv's own env_vars_required
. But, unlike env_vars_required
, it doesn't require a list of the variables to check - it checks evry on that is declared, so I believe it's less error prone. You can opt out of the check by putting (optional)
in the documentation string.
ensure_all_documented
checks that all the environment variables in .envrc
have a preceding comment matching variable name + ": " + some text
. If they don't, it prints a warning in red:

ensure_all_documented
gives a warning in red if a variable is declared without documentation.envrc.private
.envrc.private
, is excluded from the repo (via .gitignore
) and is expected to be present by .envrc
, if it's not there, direnv gives a warning:
direnv: referenced .envrc.private does not exist
So, that message will prompt the developer into creating .envrc.private
.
This file needs to set the values from .envrc
without defaults:
export SOME_REQUIRED_VARIABLE=foo
Conclusion
When a project configured in this way, setup is quite linear: README -> direnv -> create .envrc.private
. Plus, there's an opt-in for enforcement.
As things change during development, the checks ensure environment variables are set properly, and that future onboarding remains well documented.