Catch .env / .env.example drift before it causes production bugs. Zero dependencies, one command.
npx dotdriftAlmost every developer has fought .env issues — they're silent, annoying, and
usually only show up after you deploy or after a teammate clones the repo:
- You add
STRIPE_KEYto.env, ship code that reads it, but forget to add it to.env.example. A teammate clones, runs the app, and it crashes on a missing variable. .env.examplelists a key you never actually set locally — a silent misconfig waiting to bite.
The .env file and its committed .env.example template are supposed to
declare the same set of keys. They drift apart constantly. dotdrift is the
guardrail.
npx dotdrift # check .env against .env.example
npx dotdrift --strict # also flag keys whose value is empty
npx dotdrift -r # monorepo: check every service that has a pair
npx dotdrift sync # regenerate .env.example from .env (values stripped)
npx dotdrift hook # install a git pre-commit hook so you never forgetReports keys that exist in one file but not the other, and exits non-zero on drift so it drops straight into CI:
✗ drift detected between .env and .env.example
Missing in .env.example (add these so teammates know they're needed):
+ STRIPE_KEY
Tip: run "dotdrift sync" to update .env.example automatically.
Instead of nagging you to update the template by hand, sync regenerates
.env.example from .env with all values stripped. It:
- preserves your comments and blank-line grouping,
- keeps curated placeholders that already exist in the template
(e.g. a hand-written
PORT=3000survives), - is idempotent — running it twice changes nothing.
npx dotdrift sync # write the file
npx dotdrift sync --dry-run # print it instead
npx dotdrift sync --placeholder changeme # value for brand-new keysnpx dotdrift hookInstalls a .git/hooks/pre-commit that runs dotdrift check and blocks the
commit when things drift. A one-time tool becomes a continuous safety net.
| Flag | Meaning |
|---|---|
--env <path> |
env file (default .env) |
--example <path> |
template file (default .env.example) |
--strict |
treat empty values in .env as drift |
-r, --recursive |
scan subdirectories for .env/.env.example pairs |
--json |
machine-readable output |
--quiet |
no output, exit code only |
--dry-run |
(sync) print instead of writing |
--placeholder <text> |
(sync) value for brand-new keys |
| Code | Meaning |
|---|---|
0 |
in sync |
1 |
drift found |
2 |
error (missing file, bad args, not a git repo) |
Drop it into CI:
- run: npx dotdrift --strictdotdrift understands the common dotenv conventions: KEY=value,
export KEY=value, single/double quotes, KEY= (empty), # comments, and
inline comments on unquoted values. It only ever compares key names (and,
with --strict, whether a value is empty) — it never prints or transmits your
secret values.
MIT