.env.example looks harmless and boring, which is exactly why teams underestimate it. Handled correctly, it’s the contract for your application’s configuration: a single source of truth that tells every developer, CI job, and server what environment variables are expected without ever exposing real secrets. Handled badly, it becomes a half-broken copy of .env, a source of confusion, and occasionally a stepping stone to leaking secrets.
This page is a permanent reference for how to treat .env.example in Laravel (and similar frameworks), how to structure it, and how to integrate it into team workflows and secret management. Laravel’s own configuration docs reinforce the same pattern: env-driven config with sane defaults and no secrets in Git.
What .env.example is used for
At its core, .env.example is a template for your real environment file (.env in Laravel).
1. Onboarding new developers
For a new developer, .env.example answers:
- Which environment variables are required?
- Which ones are optional?
- What shape and type values should have?
- What needs real credentials vs. what can stay as default?
cp .env.example .env
php artisan key:generate
# then fill in the blanks: DB credentials, mail, queue, etc.
Without a maintained .env.example, onboarding turns into guessing, Slack messages, and “just send me your .env” (which is a security red flag).
2. Defining expected environment keys
.env.example acts as a living schema for environment variables:
- It lists all keys your app expects.
- It shows grouping and naming conventions.
- It reveals dependencies (e.g. enabling a feature requires several keys to be set).
Think of it as a config.yml for humans, but implemented with env vars for the framework.
3. Preventing real secrets from being committed
The reason .env.example exists instead of committing .env is simple:
.envcontains real values: database passwords, API tokens, signing keys..env.examplecontains placeholders or safe defaults, which can be public.
By committing only .env.example you document the configuration shape, but you avoid committing real secrets to Git, CI logs, or anywhere else they can linger.
Common misconceptions & mistakes
1. Storing real values in .env.example
This is the most dangerous mistake: copying .env → .env.example and committing it.
Problems:
- Secrets land in version control and history.
- Public or shared repos now expose your infrastructure.
Fix: .env.example should never contain live credentials, private keys, or long-lived secrets.
2. Treating it as a second .env
Some teams treat .env.example like a dev environment and keep working values inside it. Result: confusion about source of truth and drift between files.
Fix: reference-only. The app should load from .env (or injected env vars), not from .env.example.
3. Missing required keys
Incomplete templates lead to failing migrations, broken CI, and silent misbehavior.
Fix: treat missing keys as a bug; keep .env.example in sync with code expectations.
Recommended conventions for .env.example
1. Naming the file
- Use
.env.examplein the project root. - If you keep multiple templates, name them explicitly (e.g.,
.env.staging.example), but most teams only need one plus a secret manager.
Pair the file naming with consistent key naming from the ENV naming conventions guide so templates stay readable across services.
2. What should be in .env.example?
Include: required keys, important optional keys, safe defaults (e.g., APP_ENV=local).
Avoid: real credentials or environment-specific secrets.
APP_NAME="Your App Name"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database
DB_USERNAME=your_db_user
DB_PASSWORD=your_db_password
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.test"
MAIL_FROM_NAME="${APP_NAME}"
Placeholders are non-sensitive and clearly not real. This can be safely committed.
3. Required keys — “must not boot without these”
Ensure .env.example lists the essentials: APP_ENV, APP_DEBUG, APP_URL, APP_KEY (blank placeholder), DB connection details, cache/session/queue drivers.
4. Default placeholders
Make placeholders obviously fake and descriptive (e.g., DB_PASSWORD=<your-local-db-password>). Avoid cute or real-looking defaults.
Security implications
1. Why real secrets should never be included
Committed secrets propagate to every clone, fork, backup, and CI artifact. Assume anything in Git may one day be exposed.
2. APP_KEY considerations in Laravel
APP_KEY=
# or
# APP_KEY=base64:your-generated-key-here
- Generate per environment with
php artisan key:generate. - Never reuse keys across environments; never commit real keys.
- If exposed, rotate and assume encrypted data is compromised.
3. Common leak patterns
- Copying
.env→.env.exampleto “share config”. - Zipping projects with
.envand sharing in tickets or chat. - Public repos including
.envfrom a bad.gitignore. - Backups or CI artifacts storing
.env.
Mitigations: keep .env ignored, never copy it into tracked files, educate the team, and use a secret manager. The OWASP Secrets Management Cheat Sheet is a solid checklist for hardening these practices.
.env
.env.*
!.env.example
Team workflow best practices
1. Keeping .env.example in sync
- When you add an env variable in code, update
.env.examplein the same PR. - Code review checklist: “Did you touch env variables? If yes, is
.env.exampleupdated?” - Optional: CI checks that required keys exist.
2. Using validation rules
Validate critical env vars early. Example (conceptual):
$required = [
'APP_ENV',
'APP_URL',
'DB_CONNECTION',
'DB_HOST',
'DB_DATABASE',
'DB_USERNAME',
];
foreach ($required as $key) {
if (empty(env($key))) {
throw new RuntimeException(\"Missing required environment variable: {$key}\");
}
}
3. How modern secret managers help
Secret managers store sensitive values centrally, provide audited access, and enable rotation without touching Git. .env.example remains the template, while real secrets are injected at deploy/runtime. Whether you prefer HashiCorp Vault or AWS Secrets Manager, the workflow stays the same.
How Ghostable helps
- Validating expected keys: flag missing or extra variables across environments.
- Preventing drift: track changes so
.env.example, local files, and remote configs stay aligned. - Safe sharing: share structure and values securely without passing raw
.envfiles around.
Need tooling around these habits? Ghostable bakes validation, sync, and secure sharing into one workflow.
Conclusion
.env.example is a contract for how your application is configured. Keep it complete and up to date, never store real secrets inside it, enforce validation and sync in your workflows, and pair it with a proper secret management strategy. You’ll get faster onboarding, fewer config outages, and less risk of leaks.
FAQ
.env that documents expected environment variables and their shapes—without exposing secrets.
APP_KEY values.
.env.example at the project root. If you keep multiple templates, use explicit names like .env.staging.example.
.env — it loads at runtime and should not be committed. .env.example is the committed template.