Environment Variables: A Guide to Configuration Management
What Are Environment Variables?
Environment variables are key-value pairs injected at runtime to configure how applications behave without altering source code. They empower configuration flexibility across local development, CI/CD pipelines, containers, and cloud deployments.
Why Environment Variables?
Purpose | Description |
---|---|
๐ Security | Secrets (e.g. API keys, DB creds) stay out of source code. |
๐งฑ Separation of concerns | Decouple config from application logic. |
๐ Environment switching | Seamlessly change configs between dev, staging, production. |
๐ Dynamic behaviour | Enable feature toggles, flags, and runtime settings. |
Who Needs to Manage Env Vars?
Role | Usage Example |
---|---|
Developers | Local setup via .env
|
DevOps Engineers | Inject env vars in containers, CI/CD workflows |
Sysadmins | Set OS-level vars or orchestrate secrets |
Security Teams | Manage secret stores and access control |
When Should You Use Env Vars?
Use them when:
- Switching between dev/staging/prod configurations
- Storing sensitive credentials
- Managing external service URLs
- Enabling/disabling feature flags
Avoid using env vars for static or non-sensitive content that won’t change between environments.
Common Mistakes
โ Mistake | ๐ฅ Risk / Issue |
---|---|
Committing .env files |
Secrets leaked in public/private repos |
Storing secrets in frontend code | Exposes API keys and tokens |
No .env.example
|
Hard for others to set up project |
Missing defaults or fallbacks | App crashes without required variables |
Overloaded .env
|
Difficult to manage, prone to typo errors |
Using env() in Laravel outside config |
Caches won’t work as expected after deployment |
Missing variable validation on boot | Harder to debug issues due to missing context |
Pros and Cons
โ Pros | โ Cons |
---|---|
Simplifies configuration across environments | Flat structureโhard to organise without convention |
Keeps secrets out of source code | Prone to accidental exposure if misused |
Integrates seamlessly with CI/CD and containers | Lacks validation/type safety without additional tools |
Enables dynamic runtime behaviour | Debugging missing vars can be challenging |
Best Practices by Context
Development
Practice | Recommendation |
---|---|
Use .env and .env.local
|
For personal overrides |
Include .env.example
|
With placeholders only |
.env in .gitignore
|
Always |
Use dotenv loaders | E.g. vlucas/phpdotenv , dotenv , etc. |
Production
Practice | Recommendation |
---|---|
Use secrets manager or CI/CD env injection | Never rely on .env in production |
Avoid baking secrets into Docker images | Pass them at runtime instead |
Inject through Kubernetes, Docker, etc. | Maintain clean separation |
Containers (Docker, Kubernetes)
Context | Strategy |
---|---|
Docker | Use --env , --env-file , or docker-compose.yml
|
Kubernetes | Use ConfigMap (non-sensitive) and Secret (sensitive), mount as env or files |
Do’s and โ Don’ts
โ Do | โ Donโt |
---|---|
Use .env.example
|
Share .env with real values |
Validate required envs at app boot | Assume presenceโuse null fallbacks without warning |
Document env usage | Leave other developers guessing |
Store secrets securely | Hardcode them or expose in front-end |
Use consistent naming (APP_ , DB_ , etc.) |
Use vague or conflicting keys |
Framework-Specific Tips
โ Laravel
๐น Tip | ๐ ๏ธ How to Use |
---|---|
Use env() ONLY in config files |
Access with config('app.name') , not env()
|
Publish .env.example
|
To onboard teams easily |
Use config caching in production | Run php artisan config:cache
|
โ Node.js (Express, NestJS)
๐น Tip | ๐ ๏ธ How to Use |
---|---|
Use dotenv to load .env
|
require('dotenv').config() |
Validate using packages like envalid
|
For type safety and default values |
Never expose secrets in React/Vue apps | Use REACT_APP_* only for non-sensitive configs |
โ Python (Django, FastAPI)
๐น Tip | ๐ ๏ธ How to Use |
---|---|
Use python-dotenv or os.environ.get()
|
Load .env into environment |
Leverage pydantic in FastAPI |
Define env schema via BaseSettings
|
Use decouple for Django projects |
Clean separation of code and config |
โ Go
๐น Tip | ๐ ๏ธ How to Use |
---|---|
Use os.Getenv("KEY")
|
Native approach |
Consider packages like godotenv , viper
|
For dotenv support and defaults |
Avoid panic on missing keys | Provide fallbacks or error out clearly |
โ Java (Spring Boot)
๐น Tip | ๐ ๏ธ How to Use |
---|---|
Use application.properties with env vars |
${ENV_VAR:default} |
Prefer @Value or @ConfigurationProperties
|
For injection and typing |
Use secrets or ConfigMap in Kubernetes |
Spring supports externalised config out-of-box |
โ Others (Ruby on Rails, .NET, etc.)
Framework | Tip |
---|---|
Ruby on Rails | Use dotenv-rails , Figaro , or Rails.application.credentials
|
.NET Core | Use IConfiguration to bind from environment or secrets |
๐งช Suggested Validation Strategy (General)
# Example shell script to check required envs before starting app
REQUIRED_VARS=("DB_HOST" "DB_USER" "DB_PASS" "APP_KEY")
for var in "${REQUIRED_VARS[@]}"
do
if [[ -z "${!var}" ]]; then
echo "โ Missing required env variable: $var"
exit 1
fi
done
Or, use programmatic validation (e.g., pydantic
, envalid
, custom boot checkers).
๐ Final Notes for Teams
-
Onboarding: Share
.env.example
, keep instructions up-to-date - Security: Rotate secrets, use proper access control
- Monitoring: Alert on missing/misconfigured env vars
- CI/CD: Never echo secrets in build logs
Photo by Bernd ๐ท Dittrich on Unsplash