Local Configuration with .env Files
Developers create a .env file in the project root to hold values that differ between machines. Typical entries include database connection strings, Redis URLs, and test API keys. The file is loaded early in the application startup so that the rest of the code can read values through the standard environment. Because the file lives only on the local disk, each developer can use different credentials without touching shared source.
The format supports simple KEY=value pairs, optional quoting for values that contain spaces, and comments that begin with #. Multi-line values are possible with certain parsers, though most projects keep entries short. The file is never committed, so it functions as a private scratchpad rather than shared documentation.
- Store only local or test values; never production credentials.
- Use restrictive file permissions such as chmod 600 on Unix systems.
- Avoid copying the file into Docker images; inject values at runtime instead.
Documenting Required Variables with .env.example
A .env.example file committed to the repository lists every variable the application expects. It contains placeholder text rather than real secrets, serving as both onboarding guide and schema reference. New contributors copy the example, rename it to .env, and fill in their own values. The example file also acts as a checklist during code review when new configuration is introduced.
Comments inside .env.example explain the purpose, expected format, and whether a variable is required. Teams that maintain this file reduce onboarding friction and surface missing settings before they cause runtime failures.
- Commit .env.example at the repository root.
- Mark required variables clearly in comments.
- Update the example whenever a new variable is added to the codebase.
Git Ignore Rules and Pre-Commit Protection
The .gitignore file must list every variant of the environment file that should remain private. A minimal entry covers .env, .env.local, and .env.*.local. In monorepos, each package directory may need its own ignore rule so that nested services do not leak files. Relying solely on a root-level ignore is insufficient when subdirectories contain their own .env files.
Pre-commit hooks add an automated layer. Tools such as gitleaks, detect-secrets, and git-secrets scan staged changes for patterns that resemble keys or tokens. When configured as a required hook, they block the commit before the secret reaches the repository. Server-side secret scanning on GitHub, GitLab, and Bitbucket provides a final safety net that can flag or even auto-rotate discovered credentials.
- Add ignore rules before writing the first .env file.
- Run secret scanners on every commit, not just occasionally.
- Enable repository secret scanning in the hosting platform settings.
Handling Secrets Beyond Local Development
Plain .env files are acceptable only for local development of non-critical services. Production workloads require managed secret stores that provide encryption at rest, access control, audit logs, and rotation. Options include AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, and HashiCorp Vault. These systems inject values at runtime rather than storing them in files on disk.
When encrypted file solutions such as SOPS or git-crypt are used, the decrypted values still exist in memory as environment variables. The additional protection applies mainly to the version-control layer. For any deployment that handles sensitive data, a dedicated secrets manager remains the recommended approach.
- Never rely on .env files for production secrets.
- Prefer short-lived credentials and automatic rotation where possible.
- Audit access logs regularly to detect unexpected reads.
Practical Steps and Common Pitfalls
Start every new project by creating .gitignore entries and a .env.example file. Validate that the application fails fast when a required variable is missing. This practice surfaces configuration problems at startup rather than during later runtime errors. Review the example file during pull-request checks to confirm that new variables are documented.
A committed secret can be recovered from Git history even after deletion. The 2022 Toyota incident demonstrated how a single public commit exposed customer records for weeks until rotation completed. Prevention through ignore rules and scanners is far less costly than post-incident remediation.
- Test that the application starts correctly with only the example file present.
- Rotate any secret that was accidentally committed, even if later removed.
- Document the rotation process so the team can respond quickly.