Environment Variables Best Practices
Understand how to organize, name, secure and manage environment variables across development, testing and production environments.
Environment variables provide a simple way to supply configuration values to an application without hardcoding them directly into source code. They are commonly used for API URLs, database connections, application settings, feature flags and credentials that vary between environments.
Using environment variables effectively requires more than creating a .env file and adding key-value pairs. Good naming conventions, clear separation between environments, secure handling of secrets and consistent configuration practices help applications remain easier to deploy, maintain and troubleshoot.
What Are Environment Variables?
An environment variable is a named value provided to a process by its execution environment. Applications can read these values at runtime and use them as configuration instead of embedding environment-specific settings directly in the source code.
DATABASE_URL=postgresql://localhost:5432/app
API_BASE_URL=https://api.example.com
LOG_LEVEL=infoWhy Environment Variables Matter
The same application is often deployed to several environments. Development, testing, staging and production may use different databases, API endpoints, credentials and feature settings. Environment variables allow the application code to remain largely unchanged while the configuration changes around it.
- Separate configuration from application code.
- Use different settings in different environments.
- Avoid hardcoding environment-specific values.
- Simplify deployment configuration.
- Reduce accidental exposure of sensitive values.
- Make applications easier to configure in CI/CD systems.
Configuration vs Secrets
Not every environment variable is a secret. Values such as log levels, feature flags and API URLs may be ordinary configuration, while database passwords, private keys and API credentials require stronger protection.
| Type | Examples | Handling |
|---|---|---|
| General configuration | LOG_LEVEL, APP_NAME | Normal configuration |
| Environment-specific configuration | API_URL, PORT | Separate by environment |
| Sensitive values | DATABASE_PASSWORD, API_KEY | Use secure secret storage |
| Cryptographic secrets | PRIVATE_KEY, JWT_SECRET | Protect with dedicated secret management |
Use Clear Naming Conventions
Environment variable names should be predictable and easy to understand. Most projects use uppercase letters with underscores between words. A consistent naming convention makes configuration easier to search, review and maintain.
DATABASE_URL
DATABASE_HOST
DATABASE_PORT
DATABASE_NAME
API_BASE_URL
LOG_LEVEL
ENABLE_CACHEUse Descriptive Names
Environment variable names should communicate what the value represents. Generic names can become confusing as an application grows, especially when several services or external systems are involved.
| Prefer | Avoid |
|---|---|
| DATABASE_URL | URL |
| REDIS_HOST | HOST |
| PAYMENT_API_KEY | KEY |
| PUBLIC_API_BASE_URL | API |
| SESSION_TIMEOUT | TIMEOUT |
Keep Environment Files Organized
Projects may use multiple environment files for different purposes. The exact naming convention depends on the framework and deployment system, but the important principle is to make the purpose of each file obvious.
.env
.env.local
.env.development
.env.test
.env.productionA project should clearly document which environment files are intended for local development and which values are supplied by deployment infrastructure. Avoid creating a large collection of overlapping files without a defined purpose.
Never Commit Secrets
Sensitive credentials should not be committed to source control. A Git repository may preserve old versions of files even after a secret is deleted, which means accidentally committing a password or API key can have consequences long after the visible file has been changed.
.env
.env.local
.env.productionCommit an Environment Template
Although real secret values should remain outside the repository, teams often benefit from committing a template that documents which variables the application expects. The template contains placeholder values rather than real credentials.
DATABASE_URL=
DATABASE_USER=
DATABASE_PASSWORD=
API_BASE_URL=
API_KEY=
LOG_LEVEL=infoUse Placeholders Carefully
Template files should clearly distinguish placeholders from real values. Avoid placing credentials that look valid inside example configuration because developers may accidentally reuse them in real environments.
DATABASE_URL=postgresql://USER:PASSWORD@HOST:5432/DATABASE
API_KEY=your-api-key-here
JWT_SECRET=replace-with-a-secure-secretValidate Required Variables
Applications should fail early when required configuration is missing or invalid. Without validation, a missing environment variable may cause an unrelated error later in application execution, making the original configuration problem difficult to identify.
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) {
throw new Error("DATABASE_URL is required.");
}Validation can also check whether values have the correct format. For example, a port should be numeric, a URL should use an expected format and a required secret should not be empty.
Define Required and Optional Variables
| Variable | Type | Example |
|---|---|---|
| DATABASE_URL | Required | Database connection string |
| API_BASE_URL | Required | External API endpoint |
| LOG_LEVEL | Optional | info |
| ENABLE_CACHE | Optional | true |
| PORT | Optional | 3000 |
Document which variables are mandatory and which have safe defaults. This prevents developers and deployment systems from having to guess how missing values should be handled.
Use Safe Defaults
Optional configuration can use sensible defaults when the application can operate safely without an explicit value. Defaults should never silently replace required credentials or critical production configuration.
const port = Number(process.env.PORT || 3000);
const logLevel = process.env.LOG_LEVEL || "info";Treat Environment Variables as Strings
Environment variables are generally provided to applications as strings. Applications should explicitly convert values when they represent numbers, booleans or other structured data.
const port = Number(process.env.PORT);
const debug = process.env.DEBUG === "true";
const timeout = Number(process.env.REQUEST_TIMEOUT);Explicit conversion avoids subtle bugs caused by assuming that a value such as 3000 or false is already a JavaScript number or boolean.
Be Careful With Boolean Values
A common mistake is treating an environment variable directly as a boolean. Since the value is usually a string, even the text "false" is truthy in JavaScript.
const enabled = process.env.ENABLE_CACHE === "true";Separate Public and Private Configuration
Some frameworks expose specially prefixed environment variables to browser-side code. Any variable intended for client-side exposure should be treated as public configuration because users can inspect values delivered to the browser.
| Configuration | Visibility |
|---|---|
| Server-only secret | Keep on the server |
| Database credentials | Server only |
| Private API key | Server only |
| Public API URL | May be client-visible |
| Public feature flag | May be client-visible |
Avoid Duplicating Configuration
Configuration becomes difficult to maintain when the same value is duplicated across multiple environment files, deployment systems and application configuration files. Define clear ownership for each value and avoid unnecessary copies.
Keep Configuration Close to Its Purpose
Environment variables should represent meaningful application configuration rather than becoming a general-purpose storage mechanism. A project with hundreds of unrelated variables becomes difficult to understand and troubleshoot.
- Use variables for runtime configuration.
- Keep complex application data in appropriate storage.
- Avoid storing large JSON documents in environment variables.
- Avoid duplicating constants that never change between environments.
- Group related variables using consistent prefixes.
Use Prefixes for Related Variables
Prefixes can make large configuration sets easier to navigate. They are especially useful when an application integrates with multiple external services.
DATABASE_HOST
DATABASE_PORT
DATABASE_NAME
REDIS_HOST
REDIS_PORT
STRIPE_API_KEY
STRIPE_WEBHOOK_SECRETProtect Secrets in Production
Production secrets should preferably be supplied by the hosting platform, deployment system or dedicated secrets manager instead of being stored in application source repositories. This provides better access control, auditing and rotation capabilities.
| Approach | Typical Use |
|---|---|
| Local .env file | Developer machine |
| CI/CD secret storage | Automated deployments |
| Hosting platform variables | Application runtime |
| Dedicated secret manager | Sensitive production credentials |
Rotate Sensitive Credentials
API keys, database passwords and signing secrets should be replaceable without requiring application source code changes. Regular rotation limits the lifetime of credentials and reduces the impact of accidental exposure.
Do Not Log Secrets
Environment variables can accidentally appear in logs, error reports or debugging output if an application prints configuration objects. Sensitive values should always be excluded from diagnostic output.
console.log({
databaseUrl: process.env.DATABASE_URL,
apiKey: process.env.API_KEY,
});Logging configuration like this can expose credentials in application logs or monitoring systems. Log only safe metadata and explicitly redact sensitive values when configuration needs to be inspected.
Use Consistent Configuration Across Environments
Development, staging and production should use the same variable names whenever possible. The values can differ, but changing the variable names between environments creates unnecessary deployment complexity.
| Variable | Development | Production |
|---|---|---|
| DATABASE_URL | Local database | Managed database |
| API_BASE_URL | Local API | Production API |
| LOG_LEVEL | debug | info |
| ENABLE_CACHE | false | true |
Document Environment Variables
Every important environment variable should have a clear description. Documentation should explain what the variable controls, whether it is required, whether it is secret and which environments use it.
| Variable | Required | Secret | Description |
|---|---|---|---|
| DATABASE_URL | Yes | Yes | Database connection string |
| API_BASE_URL | Yes | No | Backend API endpoint |
| LOG_LEVEL | No | No | Application logging level |
| JWT_SECRET | Yes | Yes | Token signing secret |
Common Mistakes
Most environment variable problems come from inconsistent naming, missing validation, accidental exposure or unclear separation between environments. These mistakes can cause deployment failures and, in the case of secrets, serious security incidents.
- Committing .env files containing real credentials.
- Using unclear or inconsistent variable names.
- Assuming environment variables are numbers or booleans.
- Exposing private variables to browser-side code.
- Logging complete configuration objects.
- Using fake defaults for required secrets.
- Failing to document required variables.
- Using different variable names in different environments.
- Keeping unnecessary duplicate configuration.
- Never rotating credentials after exposure.
Best Practices Checklist
- Use uppercase names with consistent separators.
- Choose descriptive names that clearly communicate purpose.
- Keep sensitive values out of source control.
- Commit a safe environment template when appropriate.
- Validate required variables during application startup.
- Convert strings explicitly into numbers and booleans.
- Keep server-only secrets away from browser code.
- Use secure secret storage in production.
- Avoid logging sensitive configuration.
- Document important variables and their purpose.
- Use consistent variable names across environments.
- Rotate credentials when necessary.
Frequently Asked Questions
Should environment variables be stored in Git?
Non-sensitive templates can be committed, but real credentials and private secrets should not be stored in the repository. A committed environment template is useful for documenting required variables without exposing their values.
Are environment variables secure?
Environment variables can be a useful way to provide configuration, but they are not inherently secure. Access permissions, deployment configuration, logging practices and secret management determine how well sensitive values are protected.
Should every environment use the same variables?
Usually yes. Keeping variable names consistent across development, testing, staging and production simplifies deployments. The values can differ between environments.
How should environment variables containing numbers be handled?
Environment variables are generally strings, so numeric values should be explicitly converted before use. For example, Number(process.env.PORT) can convert a port value into a JavaScript number.
Can frontend applications use environment variables?
Yes, but developers must understand which variables are exposed to browser code. Any value included in a client-side bundle should be considered public and must not contain confidential credentials.
What should I do if an environment variable secret is leaked?
Treat the secret as compromised. Revoke or rotate the credential, remove exposed values from relevant systems and review repository history, logs and deployment systems to determine where the secret may have been exposed.
Helpful Configuration Tools
An Environment Variable Generator helps create consistent variable templates, an Environment Variable Formatter keeps configuration files readable, an Environment Variable Comparator helps identify differences between environments, a dotenv Parser extracts and analyzes variables from dotenv files, and a dotenv Cleaner helps remove unnecessary or malformed entries from environment configuration.
Conclusion
Environment variables are a fundamental part of application configuration, but using them effectively requires consistent conventions and careful security practices. Clear names, documented variables, validated configuration, separate environments and secure secret management make applications easier to deploy and maintain. By keeping credentials out of source control, avoiding accidental client-side exposure and treating configuration as part of the application's architecture, development teams can build deployment workflows that are more reliable, secure and easier to manage.