Environment variables and secrets should move through local, staging, and production in different ways. This guide provides a practical configuration model, naming convention, promotion workflow, review checklist, and recurring maintenance schedule for keeping application settings useful without turning source control, CI logs, or deployment artifacts into accidental secret stores.
Overview
Most web applications need two broad categories of configuration. Non-sensitive variables describe how an application should run, such as an environment name, public API URL, feature flag, logging level, region, or port. Secrets authenticate the application to another system, including database passwords, private API keys, signing keys, webhook credentials, and service tokens.
Both categories are often exposed to an application through environment variables, but they should not be managed identically. An environment variable is an interface used by the running process; it is not automatically a secure storage system. A value can still be exposed through a committed .env file, a build artifact, a process inspection tool, an error report, a shell history entry, or an over-verbose CI log.
A useful rule is to separate configuration by environment and ownership:
- Local: Developers use private, machine-specific files or local secret stores. These files should be ignored by version control.
- Staging: A controlled environment uses values managed by the deployment workflow or a secret manager. Staging should resemble production without sharing production credentials.
- Production: Runtime configuration comes from an approved deployment or cloud secret-management system, with restricted access, auditability, and a defined rotation process.
The safest promotion model is to promote code and configuration intent, not secret values. A pull request can define that PAYMENTS_API_KEY is required, while the actual value is supplied separately by the appropriate environment owner or platform.
What to track
1. A variable inventory
Maintain a small inventory that records each variable’s purpose, type, required environments, owner, and handling method. Do not place the secret itself in the inventory. A useful template is:
NAME: DATABASE_URL
PURPOSE: Application database connection
TYPE: secret
REQUIRED IN: local, staging, production
SOURCE: local secret file; environment-specific secret manager
OWNER: Backend team
ROTATION: On provider change, suspected exposure, or scheduled review
VALIDATION: Application startup and database health check
For public or non-sensitive settings, identify whether a value is safe to expose to a browser. Many frontend frameworks deliberately bundle variables with a public prefix into client-side JavaScript. Treat that prefix as an exposure mechanism, not as a security boundary. Never use a public client-side variable for a private credential.
2. Naming and schema conventions
Choose names that communicate purpose and remain consistent across services. Uppercase snake case is common, but consistency matters more than the style itself. Prefer REDIS_URL, SESSION_SECRET, and PUBLIC_API_BASE_URL over vague names such as KEY, URL, or CONFIG.
Document whether empty values are valid, whether a variable is required, and what format it expects. Validate configuration at startup where possible. A service should fail clearly when a required production secret is missing rather than start partially and fail later during a request.
3. The storage decision
Use local .env files for developer convenience, but commit only a safe example such as .env.example. The example should contain names, comments, and non-sensitive placeholders, never working credentials. A developer may use a local secret manager or an approved password manager when the project requires stronger controls.
For CI/CD, store secrets in the provider’s protected secret facility or connect the pipeline to a dedicated cloud secrets manager. For production, prefer runtime retrieval or controlled injection from a cloud secret manager, depending on the application platform. Keep access scoped to the service and environment rather than granting every developer or pipeline broad access.
Configuration errors often surface alongside API failures. When troubleshooting, use a disciplined request trace and inspect whether the application received the expected non-secret settings; avoid printing secret values. The API debugging workflow is a useful companion for separating configuration problems from HTTP and application errors.
Cadence and checkpoints
Configuration management works better as a recurring review than as a one-time setup task. Use the following checkpoints:
Every change
- Confirm new variables are documented and named consistently.
- Classify each value as public configuration or secret data.
- Check that no secret appears in source code, test fixtures, screenshots, logs, or pull-request output.
- Update local setup instructions and the safe environment example.
- Test missing, malformed, and environment-specific values.
Before promoting to staging or production
- Compare the application’s required configuration with the target environment’s inventory.
- Verify that staging uses separate credentials, databases, signing keys, and third-party accounts where separation is required.
- Confirm the deployment identity can read only the secrets it needs.
- Review build and deployment logs for masked values and accidental output.
- Run a smoke test that checks startup, database connectivity, authentication, background jobs, and external integrations without revealing credentials.
Monthly or quarterly
Review variable ownership, unused entries, access permissions, deployment failures, and recent provider or framework changes. Confirm that rotation instructions still work and that an engineer other than the original author can perform them. A recurring review should also check whether a secret has gradually spread into scripts, documentation, local machines, or ad hoc automation.
How to interpret changes
A changed value is not automatically a security incident. First classify the change. A URL may change because an environment was rebuilt; a feature flag may change because a release is being tested; a credential may change because of routine rotation. The response depends on the variable’s sensitivity, scope, and source.
Unexpected changes deserve a traceable explanation. Check the deployment record, recent infrastructure changes, secret-manager audit information, and application startup logs. Compare names and metadata rather than copying secret values into tickets or chat. If a value may have been exposed, treat it as compromised: restrict its use, replace it through the approved process, identify affected services, and record the incident and follow-up actions.
Rotation should be designed as an operational procedure, not an emergency-only action. Where a provider supports overlapping credentials, create the replacement, deploy consumers, verify successful use, and then revoke the old value. If overlap is not possible, schedule a controlled maintenance window or use a staged deployment plan. Update the inventory after every rotation so the documented owner and source remain accurate.
Do not confuse encoding with protection. Base64, URL encoding, and similar transformations make data portable or readable; they do not make a secret confidential. The developer text utilities guide can help with legitimate encoding tasks, but encoded credentials should still be handled as secrets.
When to revisit
Revisit this article and your project’s configuration inventory at least monthly or quarterly, based on the sensitivity and change rate of the system. Review it immediately after a deployment platform migration, framework upgrade, new integration, change to frontend build behavior, access-control change, or suspected credential exposure. Provider terminology and secret-injection features can change, so verify implementation details against the current documentation for your chosen platform before making a change.
Use this short action list during the next review:
- Export the list of variables expected by the current application version.
- Compare it with local documentation, CI/CD settings, staging, and production.
- Remove unused variables and narrow permissions where possible.
- Check that no production credential is reused in local or staging systems.
- Test the documented rotation and recovery procedure.
- Record owners, dates, exceptions, and follow-up work.
A clean separation between code, configuration, and secrets makes deployments easier to reason about. It also gives teams a repeatable way to diagnose failures, rotate credentials, and onboard developers without passing sensitive values through source control or informal communication.