Every application depends on configuration: database credentials, API keys, mail settings and feature flags. Handled carelessly, these values end up in Git history, chat messages and screenshots. Handled well, they are easy to change, hard to leak and consistent across environments.
Separate code from configuration
The same code should run in development, staging and production, with only configuration changing between them. Read settings from environment variables rather than hard-coding them. Frameworks like Laravel load a .env file in development and read real environment variables on servers.
Never commit secrets
Add .env to .gitignore from day one and commit a .env.example that lists every variable with a harmless placeholder. New developers copy it and fill in their own values.
APP_ENV=local
DB_HOST=127.0.0.1
DB_PASSWORD=change-me
PAYMENT_API_KEY=
Add a secret scanning tool to your pre-commit hooks and continuous integration. Many Git hosts can also scan pushes and block commits that contain recognisable keys.
If a secret leaks, rotate it
Deleting a committed key in a later commit does not remove it from history, and anyone who cloned the repository still has it. Treat any leaked secret as compromised: revoke it, issue a new one and update every environment. Rewriting history is a cleanup step, not a fix.
Validate configuration at boot
Missing variables often surface as confusing errors deep in the application. Fail fast instead: check that required values exist when the app starts or during deployment.
foreach (['DB_PASSWORD', 'PAYMENT_API_KEY'] as $key) {
if (blank(env($key))) {
throw new RuntimeException("Missing required config: {$key}");
}
}
In Laravel, only call env() inside config files and use config() everywhere else. Once configuration is cached for performance, direct env() calls elsewhere may return null.
Share secrets through proper channels
Pasting credentials into team chat or email leaves copies in places you do not control. Use a password manager with shared vaults for small teams, and give each developer their own development keys where providers allow it.
Move to a secrets manager as you grow
Cloud platforms and dedicated tools offer secrets managers that store values encrypted, control who can read them, log access and support rotation. Your deployment pipeline fetches secrets at release time and injects them as environment variables, so they never sit in a file on a developer's laptop.
Apply least privilege
- Separate keys per environment. A staging key should never work against production data.
- Scope permissions narrowly. A service that only sends email does not need full account access.
- Use read-only database users for reporting and analytics.
- Set expiry dates on tokens where the provider allows it.
Keep secrets out of logs and errors
Debug pages, stack traces and verbose logs can print environment variables. Disable debug mode in production, mask sensitive keys in error reporting tools and avoid logging full configuration objects.
Rotate on a schedule
Routine rotation limits the damage of a leak nobody noticed. Start with the most powerful credentials, such as database root passwords and payment keys, and document how to rotate each one without downtime. Rotation also needs to happen whenever someone with access leaves the team.
Onboarding and offboarding
When someone joins, give them their own development credentials rather than sharing a colleague's. When someone leaves, remove their access to secrets managers, cloud consoles and third-party dashboards on their last day, and rotate any shared credentials they could have seen. A short checklist for both moments prevents forgotten access from lingering for months.
Wrapping up
Treat configuration as part of your security posture. Keep secrets out of Git, provide an example file, validate on boot, share through a password manager or secrets manager, scope keys tightly and rotate them. These habits are cheap to adopt early and expensive to retrofit after an incident.