.env and .env.example serve different purposes
- .env
- Local values, often including real credentials or machine-specific configuration. Normally excluded from Git.
- .env.example
- A versioned template listing the required variable names, safe placeholders, and setup comments.
Build the template without copying secrets
- Read the local configuration without copying the file into the repository.
- Keep only variables actually required for setup.
- Replace credentials and private endpoints with clearly fictional placeholders.
- Keep harmless defaults only if they are valid in every environment.
- Describe the expected format and where authorised developers obtain the real value.
- Confirm that .env and local variants are ignored, then inspect the diff before committing.
Use unmistakable placeholders
The example below documents names and formats while making it hard to mistake the placeholders for working production credentials. A partially masked real token is not a placeholder.
# Public local application URL
APP_BASE_URL=http://localhost:4200
# Required. Obtain your own key from the provider.
OPENAI_API_KEY=your_api_key_here
# Required for a local development database.
DATABASE_URL=postgresql://user:replace_me@localhost:5432/app_db
# Optional. Enable only for local development.
DEBUG=false A frontend environment variable is still public
If a build embeds a key in browser code, visitors can inspect it in the bundle or network requests. Prefixes such as PUBLIC_ and VITE_ commonly signal client-exposed values. Server credentials belong in a backend, serverless function, or another protected environment—not in a browser bundle.
- Treat API keys, OAuth tokens, passwords, private keys, signing secrets, and connection strings as secrets.
- Treat a URL with embedded credentials as a secret too.
- If a key can spend money or read or change data, it is not frontend-safe.
If a secret was already committed
Deleting the line in the latest commit does not erase it from history, forks, CI logs, or caches. Revoke or rotate the credential at the provider first. Then remove it from code, fix ignore rules, inspect exposure, and coordinate any history cleanup with the repository team.