Skip to main content

Keep .env.example in sync with .env and validate environment variables before boot. Detect missing, extra and empty env vars in CI. A zero-dependency dotenv-linter alternative that stops apps crashing on a missing variable.

Project description

🔐 envsync

Keep .env.example in sync with .env — and never boot with a missing variable again.

The number one "works on my machine" bug: someone adds STRIPE_KEY to their .env, forgets to update .env.example, and a teammate's app crashes with a cryptic error. envsync fixes both sides of that — automatically, with zero dependencies.

PyPI version Python versions zero dependencies license

Installed from PyPI as dotenv-sync; it gives you the envsync command (and a dotenv-sync alias).


The problem

.env.example is the contract every teammate copies. But it drifts the instant someone adds a variable to their local .env and forgets the template:

  • New devs cp .env.example .env, run the app → crash, because a required key was never in the template.
  • Code reviews can't see that a PR introduced a new required env var.
  • Secrets occasionally get pasted into .env.example by hand and leak into git.

The fix

uvx dotenv-sync             # add new keys from .env to .env.example (values stripped)
uvx dotenv-sync check       # CI: fail if the template drifted
uvx dotenv-sync validate    # preflight: fail if your local .env is missing required keys
$ uvx dotenv-sync
✔ added 2 key(s) to .env.example:
  + STRIPE_KEY
  + REDIS_URL

$ uvx dotenv-sync validate
✖ missing 1 required key(s) (declared in .env.example):
  ✖ DATABASE_URL
Your app may crash on boot. Fill these in .env (copy from .env.example).
  • Never leaks values. Only keys are written to .env.example (KEY=), and your curated placeholders/comments are preserved.
  • Non-destructive & idempotent. Existing lines are never touched; running twice is a no-op.
  • Zero dependencies. Installs instantly, nothing to audit.

Install

uvx dotenv-sync            # run without installing (uv)
pipx install dotenv-sync   # or install the CLI globally
pip install dotenv-sync    # or into your project

Commands

Command What it does
envsync / envsync sync Append keys in .env missing from .env.example (values stripped)
envsync check CI mode — exit 1 if .env.example is missing keys from .env
envsync validate Preflight — exit 1 if your .env is missing keys the template requires
envsync init Create .env.example from .env (values stripped) or a starter

Options: --env <file>, --example <file>, --cwd <dir>, --allow-empty, --process (also accept keys from the process environment during validate), --quiet.

Use it in CI

# .github/workflows/env.yml
name: env
on: [push, pull_request]
jobs:
  envsync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/setup-uv@v5
      - run: uvx dotenv-sync check   # fail if someone forgot to update .env.example

Pre-commit hook:

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: envsync
        name: envsync check
        entry: envsync check
        language: system
        pass_filenames: false

Preflight before your app starts

Catch missing config before a confusing runtime crash — e.g. in a container entrypoint:

envsync validate && python -m myapp

Python API

from envsync import validate

result = validate()
if not result.ok:
    raise SystemExit(f"Missing env: {result.missing}")

How keys are parsed

KEY=VALUE, export KEY=VALUE, single/double-quoted values, # comments, and blank lines. Unrecognized lines are preserved verbatim, so envsync never mangles your files.

FAQ

How do I keep .env.example in sync with .env in Python?

Run uvx dotenv-sync (or pip install dotenv-sync then envsync). It adds any key in .env that's missing from .env.example, values stripped, preserving your comments. Add uvx dotenv-sync check to CI so the build fails when the template drifts.

How do I validate required environment variables before the app starts?

uvx dotenv-sync validate reads the keys declared in .env.example and exits 1 listing any missing or empty ones in your .env or process environment — a preflight that catches misconfiguration before a confusing runtime crash.

Does it leak secrets into .env.example?

Never. Only keys are written (KEY=); values are always stripped and existing lines are preserved.

dotenv-sync vs dotenv-linter / python-dotenv / pydantic-settings?

python-dotenv/pydantic-settings load env vars; dotenv-sync keeps the template honest and validates it — sync, CI drift-check, and preflight validation, with zero dependencies. It's the Python twin of the npm envsync package (byte-identical output).

Also on npm

JavaScript project? The same tool ships on npm — npx envsync.

License

MIT — free for personal and commercial use.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dotenv_sync-1.0.0.tar.gz (5.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dotenv_sync-1.0.0-py3-none-any.whl (5.6 MB view details)

Uploaded Python 3

File details

Details for the file dotenv_sync-1.0.0.tar.gz.

File metadata

  • Download URL: dotenv_sync-1.0.0.tar.gz
  • Upload date:
  • Size: 5.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for dotenv_sync-1.0.0.tar.gz
Algorithm Hash digest
SHA256 7b8ad4c0591c3550d80cd44443fe706aaa239e7d9aa625a49f7a4b5bfeac575e
MD5 ff0d5ac3a82d270a5f9feaba57f9c566
BLAKE2b-256 f8df19bbdb7a8c3058ed1893c1f8f04a523c53f00dee2f8bfaff7d4e80829cef

See more details on using hashes here.

File details

Details for the file dotenv_sync-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: dotenv_sync-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 5.6 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for dotenv_sync-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aa82de8f8f4cc3a926eba2f7f18bec85583712d9b3d46f2c0b6e858d85fb4b89
MD5 bd148b604fef8da959bbd8886c7fa3eb
BLAKE2b-256 859aa21e61e385545b4a6191b31bddc4622d130fb2b7ecb5fd7d07d944cb3b0c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page