Real-world Laravel apps live in at least three environments: local, staging, and production. Same code, different risk levels, different secrets. A sloppy approach leaks credentials, breaks deploys, and slows teams down. A disciplined approach turns environments into a predictable workflow with clear ownership, safe rotations, and reliable rollbacks.
That discipline mirrors the 12-factor “Config” principle, which keeps code portable by injecting environment-specific settings rather than baking them into the repo.
Introduction
Multi-environment planning is about more than three .env files. It means:
- Separating code from configuration so the same build can run anywhere.
- Reducing leak paths (Git history, logs, backups, screenshots, support tickets).
- Keeping environments aligned while still allowing safe experimentation in dev.
- Making deploys repeatable and auditable with minimal manual steps.
Laravel environment basics
APP_ENVtells Laravel which environment you are in (local,staging,production, etc.). Hosting platforms often inject this for you..envis loaded at runtime and must not be committed..env.exampledocuments expected keys without secrets.- For production, prefer injected environment variables or a secret manager instead of plaintext files on disk.
- Keep
env()calls inside config files; useconfig()in application code so config caching behaves.
Need a template to start from? Use the pattern in our Laravel .env.example guide so every environment begins with the same documented baseline.
Typical multi-environment layout
A simple but effective layout:
| Environment | Purpose | Secrets / Config handling |
|---|---|---|
| Local | Developer work, rapid iteration | .env copied from .env.example; personal credentials only |
| Staging | Pre-production testing, QA, demos | .env.staging or injected variables; secrets kept outside Git |
| Production | Live traffic, compliance, high trust | Injected environment variables or secret manager; avoid plaintext files on disk |
How to manage multiple environments
Option A: separate .env-style files
# On staging or production during deploy
cp .env.production .env
php artisan config:cache
php artisan migrate --force
- Pros: simple to grasp, low tooling overhead.
- Cons: risk of commits or leaks, no access control, poor audit trail, harder rotation.
Option B: injected environment variables / secret manager
- Use platform- or OS-level environment variables, container runtime variables, or a dedicated secret manager.
- Keep secrets encrypted at rest, scoped by environment, and traceable with audit logs.
- Rotate credentials without shipping new code or artifacts.
Teams typically reach for HashiCorp Vault, AWS Parameter Store, or platform-specific secret stores to make this flow repeatable.
Recommended: templates + injected secrets
Commit templates (.env.example, optionally .env.staging.example) for documentation, but inject real values from a secret manager during deploy. This keeps expectations visible while secrets stay out of Git and build outputs.
Best practices & security
- Never commit real secrets. Only commit templates and obvious placeholders.
- Use uppercase, underscored variable names; avoid spaces or punctuation.
- Validate required keys early (bootstrap scripts or service providers) to fail fast on missing configuration.
- Cache config in staging/production (
php artisan config:cache), but remember to warm it after updates. - Back up secret stores securely and track who can read or rotate credentials.
- Document ownership: who updates staging vs. production values, and how rotations are approved.
Migration strategy: single env to multi-env + secret manager
- Audit every environment variable your app relies on; note which are sensitive.
- Create environment-specific templates (
.env.staging.example,.env.production.example) and refresh.env.example. - Choose a secret manager or hosting-level env store; populate it per environment.
- Update deploy scripts/CI to inject variables for staging and production, then run
config:cacheand any migrations. - Refactor code to read via
config()so caching is safe. - Document the workflow: who adds keys, how to rotate, how to onboard new teammates.
- Test in staging first. Verify expected keys, log redaction, and that secrets never touch artifacts.
When to use which approach
- Local development:
.envfrom.env.example; developer-owned credentials. - Shared staging: injected env vars or a secrets manager; optional
.env.stagingif tightly controlled. - Production: always injected env vars or secret manager; avoid plaintext files; enforce access controls and audit logs.
- Frequent rotations or multiple services: secret manager + environment-aware config, with validation to prevent drift.
How Ghostable helps
- Environment templates: keep
.env.exampleaccurate and in sync with staging/production expectations. - Validation: catch missing or extra keys before deploy; enforce parity across environments.
- Secure sharing: share secrets without passing around files; audit who accessed what, and when.
- Rotation and drift control: rotate credentials centrally and push updates without leaking into Git or artifacts.
Want these guardrails without gluing tools together? Ghostable ships environment templates, validation, and audited sharing out of the box.
Conclusion
Treat environments as first-class citizens. Document expected keys, keep secrets out of Git, inject values from a secure store, and validate at deploy time. With a clean workflow, local development stays fast, staging stays trustworthy, and production stays locked down.
FAQ