compareupdated

dotenv vs direnv: which env loader should you use?

dotenv loads .env inside your app at runtime. direnv loads per-directory env into your shell. Comparison of use cases, trade-offs, and when you want both.

TL;DR

  • dotenv — loads .env into your app's process at runtime. Lives inside the app.
  • direnv — loads .envrc into your shell when you cd into the directory. Lives outside the app.
  • They solve different problems. Many teams use both.

What dotenv actually does

dotenv is a library you import in your app code. On startup, it reads a .env file and merges the values into process.env. That's it. The shell you launched the app from doesn't see these variables at all.

// server.js
import 'dotenv/config';
console.log(process.env.DATABASE_URL);  // works

// terminal
$ echo $DATABASE_URL
# empty — dotenv only loaded it into the Node process

What direnv actually does

direnv is a shell extension. When you cd into a directory with an .envrc, it automatically exports those variables into your current shell. When you cd out, they unload.

$ cd ~/projects/api
direnv: loading ~/projects/api/.envrc
direnv: export +DATABASE_URL +JWT_SECRET

$ echo $DATABASE_URL
postgres://localhost/api

$ cd ..
direnv: unloading

Now every CLI tool you run — psql, redis-cli, pytest, ad-hoc scripts — sees the right values automatically. No source .env, no wrapping commands in node --env-file=.env.

When to use which

ScenarioPick
Your app needs process.env.KEY at runtimedotenv (or Node 20+ --env-file)
You want psql / redis-cli to "just work" in the project dirdirenv
Python venv + env vars activated togetherdirenv (via layout python)
CI/CD pipelinesNeither — use host env injection
ProductionNeither — host dashboard or secrets manager

Using them together

The common production-grade setup on macOS/Linux dev machines:

# .envrc (loaded into shell by direnv)
dotenv                    # loads .env into shell via direnv's dotenv helper
source .venv/bin/activate # if Python
export PATH="./node_modules/.bin:$PATH"

# .env (consumed by your app at runtime via dotenv lib)
DATABASE_URL=postgres://localhost/app
JWT_SECRET=...

Now npm run dev works (dotenv lib reads .env) and psql in your terminal hits the right DB (direnv exported DATABASE_URL to the shell).

Security considerations

Both .env and .envrc sit in your repo directory and should be git-ignored (how-to).

direnv has one safety feature dotenv doesn't: allow-listing. When you first enter a directory with an .envrc, direnv refuses to load it until you explicitly run direnv allow. This prevents a malicious git clone from exporting attacker-controlled env vars into your shell.

Switching between the two

Going from dotenv to direnv: keep .env, add a .envrc that just contains dotenv. Done.

Going from direnv to dotenv: move anything that isn't KEY=value (shell functions, PATH manipulation, venv activation) out of .envrc and into a wrapper script. What's left goes into .env.

FAQ

Can direnv load a .env file directly, or does it need its own .envrc syntax?

direnv ships a built-in dotenv function for exactly this — adding a single line, dotenv, to your .envrc loads the same .env your app already reads, so you don't maintain two copies of the same values.

Does direnv work on Windows?

Not natively — direnv is a Bash/Zsh/Fish shell hook, so on Windows it requires WSL. If your team is on native Windows without WSL, dotenv (or Node's built-in --env-file) is the more portable choice.

Is direnv's allow-list a real security boundary, or just a prompt?

It's a real one, backed by a hash of the file's contents stored outside the repo. If the .envrc changes after you've allowed it — say, a malicious edit lands via a pulled branch — direnv blocks it again until you explicitly re-run direnv allow.

Can I use direnv with Docker or a devcontainer?

direnv operates on your host shell, not inside a container, so it doesn't apply directly inside a Docker build or a running container's shell. Inside a devcontainer, install direnv as part of the container setup if you want the same behaviour there.

Recommendation

For solo projects: start with dotenv. For any team larger than one, or if you regularly run CLI tools against your dev DB, add direnv on top. The combination is the best-in-class local-dev env setup in 2026.

For production, neither of these is the answer — see our dotenv vs secrets manager comparison.

Related guides

Related tools