⚙️ .env File Validator & Formatter
Paste your .env contents — catch duplicates, bad names, unquoted spaces & trailing whitespace, then export a CI-ready clean file.
The .env File Checklist Every Dev Team Needs Before Pushing to CI
There is a specific kind of production incident that nobody talks about in post-mortems because it is too embarrassing: the deployment that failed because DB_PASSWORD=my secret was interpreted by the shell as DB_PASSWORD=my with secret treated as a stray command. Or the staging environment that silently used the wrong database because DB_HOST was defined twice and no one noticed the loader grabbed the first one. These are not architecture failures. They are .env hygiene failures, and they are entirely preventable.
This checklist walks through every category of .env bug worth catching before your file reaches a CI runner, a Docker container, or a cloud secrets manager.
1. Hunt Down Every Duplicate Key
Duplicate keys are the most dangerous .env bug because behavior on collision is undefined across tools. Node.js dotenv takes the first value. Python-dotenv takes the last. Docker Compose deduplicates arbitrarily. If your team merges a feature branch that adds REDIS_URL into a base file that already has REDIS_URL, you now have a time-bomb that detonates differently depending on which runtime loads the file first.
The fix is simple: scan every key before you deploy. A quick one-liner in bash — grep -v '^#' .env | cut -d= -f1 | sort | uniq -d — will print any duplicated key names. Automate this check in your pre-commit hook or your CI pipeline's first step, before secrets are even injected.
2. Validate Every Key Name Against the POSIX Standard
POSIX environment variable names must match [A-Z_][A-Z0-9_]*. In practice most runtimes allow lowercase, but keys that start with a digit (1API_KEY), contain hyphens (API-KEY), or have spaces (API KEY) will silently fail or throw parse errors depending on the dotenv library version. The convention used by GitHub Actions, AWS ECS task definitions, Kubernetes ConfigMaps, and virtually every CI system is UPPER_SNAKE_CASE. Enforce it early so you never debug a mysterious "key not found" error caused by apiKey versus API_KEY.
3. Quote Any Value That Contains Spaces
This is the most common source of runtime surprises. The .env spec (as interpreted by most libraries) does NOT strip unquoted inline spaces the way a shell would. Consider:
APP_DESCRIPTION=My Awesome Application
In shell sourcing (source .env), this sets APP_DESCRIPTION=My and then tries to execute Awesome as a command. In dotenv libraries, behavior varies — some capture the full string, some truncate at the first space. The safe rule: if your value contains any whitespace, wrap it in double quotes. Always. No exceptions.
APP_DESCRIPTION="My Awesome Application"
This is unambiguous across every runtime, every library, every OS.
4. Strip Trailing Whitespace from Every Line
Trailing whitespace is invisible in most editors and catastrophic in certain contexts. A password like SECRET=abc123 (with a trailing space) will cause authentication failures in systems that pass the value directly to a hashing function or an API client. Curl, psql, Redis AUTH, and JWT libraries all treat a trailing space as part of the secret value. Your editor will not show it. Your diff viewer may not highlight it. Your CI system will not warn about it. Only a deliberate validator will catch it.
Configure your editor to trim trailing whitespace on save, and add a validator check as a CI gate so the rule is enforced even when team members forget their editor settings.
5. Watch for Inline Comments Without Quoting
Some dotenv implementations support inline comments:
PORT=3000 # HTTP port
Others treat # HTTP port as part of the value. This ambiguity has bitten entire teams who switched dotenv libraries mid-project. If you need to document values, put comments on their own line above the key. Never rely on inline comment behavior unless you have verified your specific library version's parsing rules and locked that library version in your lockfile.
6. Flag Unquoted Special Characters
The characters $ # & * \ | < > ! all carry special meaning in POSIX shells. An unquoted value like DB_PASSWORD=p@$$w0rd#2024 will expand $$ to the current PID in most shells. Even in dotenv libraries that do not invoke a shell, some implement variable interpolation ($VAR expansion within values), which means DB_PASSWORD=abc$DEF may silently resolve to abc plus the current value of DEF in the environment.
The defensive rule: quote any value containing $, #, &, backslash, pipe, or angle brackets. Use single quotes if you want absolutely no interpolation, double quotes if you intentionally want variable expansion to happen.
7. Normalize Whitespace Around the Equals Sign
Technically, POSIX shell assignment syntax does not allow spaces around = in variable assignments (KEY = VALUE is a syntax error in sh). Many dotenv libraries are more lenient and strip those spaces, but not all. The dotenv-expand package, for example, behaves differently from the standard dotenv package on this edge case. Normalizing to KEY=VALUE with no surrounding spaces costs you nothing and eliminates one entire category of parser-specific bug.
8. Audit Empty Values Intentionally
An empty value (FEATURE_FLAG=) is valid syntax, but it is often a sign of a forgotten fill-in. In CI environments, secret injection systems like GitHub Actions secrets or HashiCorp Vault will refuse to inject a blank value for a key that is expected to be a secret, which surfaces as a mysterious "secret not found" error rather than a clear "this value is empty" error. Review every empty value and decide whether it is intentional (a disabled feature flag) or accidental (a missing credential placeholder).
9. Check for Sensitive Key Names Without Values
Keys that match patterns like *_SECRET, *_PASSWORD, *_TOKEN, *_KEY, or *_CREDENTIAL with empty values are almost always a CI misconfiguration waiting to cause an incident. Add a check that asserts these keys are non-empty before deployment. This is the difference between discovering a missing credential in your local test run versus discovering it when your production payments API refuses to authenticate at 2am on a Friday.
10. Run Your Validator Before Every CI Merge
All of the above checks are only valuable if they run automatically. The correct place for a .env validator is in three locations simultaneously: as a pre-commit hook (catches issues before the file is committed), as a CI step that runs before build or test (catches issues that slipped through), and as part of your secrets-loading script in production infrastructure (catches drift between the committed template and the injected values).
The .env file is the single most error-prone configuration artifact in a modern application stack because it lives at the intersection of shell parsing, library parsing, and developer convention — three things that never quite agree. A thirty-second validation pass before every deployment is the cheapest insurance you will ever buy.