0

Environment variables done right

I've seen API keys committed to Git, .env files with 50+ variables, and production secrets stored in plain text files. Here's how to manage environment variables properly.

The Basics

# .env file (development only)
DATABASE_URL=postgresql://localhost:5432/mydb
REDIS_URL=redis://localhost:6379
API_KEY=dev_key_123
PORT=3000
// Load with dotenv (Node.js)
require('dotenv').config();
const dbUrl = process.env.DATABASE_URL;

Rule #1: .env goes in .gitignore. Always.

Structure Your Variables

# .env.example (committed to Git — no real values)
DATABASE_URL=
REDIS_URL=
API_KEY=
PORT=3000

# .env.development
DATABASE_URL=postgresql://localhost:5432/mydb_dev

# .env.test
DATABASE_URL=postgresql://localhost:5432/mydb_test

# .env.production (never in Git)
DATABASE_URL=postgresql://prod-host:5432/mydb_prod

Validation at Startup

Don't wait for the first database call to discover DATABASE_URL is missing.

// config.js
const required = ['DATABASE_URL', 'REDIS_URL', 'API_KEY'];
const missing = required.filter(key => !process.env[key]);

if (missing.length > 0) {
    console.error(`Missing env vars: ${missing.join(', ')}`);
        process.exit(1);
        }
        
        module.exports = {
            db: process.env.DATABASE_URL,
                redis: process.env.REDIS_URL,
                    apiKey: process.env.API_KEY,
                        port: parseInt(process.env.PORT || '3000'),
                            isDev: process.env.NODE_ENV !== 'production',
                            };
                            ```
                            
                            ## Secrets Management (Production)
                            
                            ### Option 1: Platform secrets
                            
                            ```yaml
                            # GitHub Actions
                            env:
                              API_KEY: ${{ secrets.API_KEY }}
                              
                              # Docker Compose
                              services:
                                app:
                                    environment:
                                          - API_KEY=${API_KEY}  # From host environment
                                          ```
                                          
                                          ### Option 2: Vault/AWS Secrets Manager
                                          
                                          ```python
                                          import boto3
                                          
                                          def get_secret(name):
                                              client = boto3.client('secretsmanager')
                                                  response = client.get_secret_value(SecretId=name)
                                                      return json.loads(response['SecretString'])
                                                      
                                                      secrets = get_secret('myapp/production')
                                                      db_url = secrets['DATABASE_URL']
                                                      ```
                                                      
                                                      ### Option 3: Encrypted .env
                                                      
                                                      ```bash
                                                      # Encrypt
                                                      gpg --symmetric --cipher-algo AES256 .env.production
                                                      # Creates .env.production.gpg (safe to commit)
                                                      
                                                      # Decrypt
                                                      gpg --decrypt .env.production.gpg > .env.production
                                                      ```
                                                      
                                                      ## Common Mistakes
                                                      
                                                      1. **Default values for secrets**: `API_KEY || 'default'` — fails silently in production
                                                      2. **Logging env vars**: `console.log(config)` — prints secrets to log files
                                                      3. **Different names across environments**: `DB_URL` vs `DATABASE_URL` vs `DB_CONNECTION_STRING`
                                                      4. **Putting non-secrets in env vars**: App name, feature flags → use config files instead
                                                      
                                                      ## Docker
                                                      
                                                      ```dockerfile
                                                      # Bad: bakes secrets into image layer
                                                      ENV API_KEY=secret123
                                                      
                                                      # Good: pass at runtime
                                                      # docker run -e API_KEY=secret123 myapp
                                                      # or: docker run --env-file .env myapp
                                                      ```
                                                      
                                                      ---
                                                      
                                                      How do you manage secrets in production? Always curious about different setups.

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí