Your .env file is lying to you. I built a tiny tool to catch it.
Every new AI tool wants another API key. So my .env file kept growing β and one day I realized I no longer trusted it.
A teammate cloned the repo, followed .env.example, and the app crashed. A key that was in .env had never been added to the example. An old key that nobody used anymore was still there. And somewhere in the middle sat STRIPE_KEY=changeme, which had been there long enough that nobody noticed.
Formatters and linters check whether your .env file looks right. None of them told me whether my env setup was actually correct. So I built a small tool that does exactly that: env-doctor.
What it checks
One stdlib-only Python CLI. No dependencies, no network, no telemetry.
python -m env_doctor check --env .env --example .env.example
| Check | What it finds |
|---|---|
| Drift | Keys in .env.example missing in .env, and vice versa |
| Duplicates | Same key defined twice |
| Placeholders | Empty values, changeme, your-api-key, TODO, xxx, ... |
| Risky secrets | Known prefixes (ghp_, sk-, AKIA, ...) or long high-entropy values |
| Unused vars | Keys not referenced in scanned code (--scan .) |
| Invalid lines | Lines without =, invalid key names |
Exit code 0 means no errors, 1 means errors found. Warnings never fail the run on their own, so you can use it in CI without false failures from heuristics.
What it looks like
$ python -m env_doctor check --env examples/drift/.env --example examples/drift/.env.example
[ERROR] duplicate-key: Duplicate key 'DATABASE_URL' (line 3)
[ERROR] missing-in-env: 'NEW_API_URL' is in .env.example but missing in .env
[WARN ] placeholder-value: 'STRIPE_KEY' still looks like a placeholder value
[WARN ] missing-in-example: 'OLD_FLAG' is in .env but missing in .env.example
Summary: 2 error(s), 2 warning(s), 3 key(s).
That drift/ example ships in the repo, broken on purpose, so you can see the output immediately.
Try it in 3 steps
# 1. Clone
git clone https://github.com/techdevfun/env-doctor.git
cd env-doctor
# 2. No dependencies to install (Python 3.9+ stdlib only).
# Optional: install the `env-doctor` command
pip install -e .
# 3. Run it
python -m env_doctor check --env .env --example .env.example
A few more ways to use it:
# Clean setup β should pass
python -m env_doctor check --env examples/basic/.env --example examples/basic/.env.example
# JSON output for CI / scripts
python -m env_doctor check --env examples/drift/.env --example examples/drift/.env.example --format json
# Also flag vars not referenced in code
python -m env_doctor check --env .env --example .env.example --scan .
And in CI, it's one step:
- name: Audit .env drift
run: python -m env_doctor check --env .env --example .env.example --format text
The repo runs the same check in .github/workflows/ci.yml on Python 3.9, 3.11, and 3.12.
What's next
On the roadmap: --fix to auto-add missing keys to .env.example as empty placeholders, --strict to turn selected warnings into errors, support for .env.local / .env.production layering checks, and SARIF output for GitHub code scanning.
If you try it and it misses a case your project hits, open an issue β that's the feedback that shapes what gets built next.
Top comments (0)