Environment Management Guide
This guide covers comprehensive environment management practices for development, staging, and production environments in Trae.
Overview
Environment management is crucial for maintaining consistent, reliable, and secure development workflows. This guide covers:
- Environment configuration strategies
- Variable management
- Development environment setup
- Production deployment considerations
- Security best practices
Environment Types
Development Environment
Characteristics:
- Local development setup
- Debug mode enabled
- Hot reloading
- Development databases
- Verbose logging
Configuration:
bash
# .env.development
NODE_ENV=development
DEBUG=true
API_URL=http://localhost:3000
DATABASE_URL=postgresql://localhost:5432/myapp_dev
LOG_LEVEL=debug
HOT_RELOAD=trueStaging Environment
Characteristics:
- Production-like setup
- Testing and QA
- Performance testing
- Integration testing
- Limited debugging
Configuration:
bash
# .env.staging
NODE_ENV=staging
DEBUG=false
API_URL=https://staging-api.myapp.com
DATABASE_URL=postgresql://staging-db:5432/myapp_staging
LOG_LEVEL=info
CACHE_ENABLED=trueProduction Environment
Characteristics:
- Optimized performance
- Security hardened
- Monitoring enabled
- Error tracking
- Minimal logging
Configuration:
bash
# .env.production
NODE_ENV=production
DEBUG=false
API_URL=https://api.myapp.com
DATABASE_URL=postgresql://prod-db:5432/myapp_prod
LOG_LEVEL=error
CACHE_ENABLED=true
MONITORING_ENABLED=trueEnvironment Variables
Variable Categories
Application Configuration
bash
# Application settings
APP_NAME=MyApplication
APP_VERSION=1.0.0
APP_PORT=3000
APP_HOST=0.0.0.0Database Configuration
bash
# Database settings
DATABASE_URL=postgresql://user:password@host:port/database
DATABASE_POOL_SIZE=10
DATABASE_TIMEOUT=30000
REDIS_URL=redis://localhost:6379External Services
bash
# Third-party services
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_REGION=us-east-1
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587Security Configuration
bash
# Security settings
JWT_SECRET=your_jwt_secret_key
ENCRYPTION_KEY=your_encryption_key
API_KEY=your_api_key
SESSION_SECRET=your_session_secretVariable Management
Environment Files
File Structure:
project/
├── .env.example # Template with all variables
├── .env.local # Local overrides (gitignored)
├── .env.development # Development settings
├── .env.staging # Staging settings
├── .env.production # Production settings
└── .env.test # Test environment settingsLoading Environment Variables
Node.js Example:
javascript
// config/environment.js
require('dotenv').config({
path: `.env.${process.env.NODE_ENV || 'development'}`
});
const config = {
app: {
name: process.env.APP_NAME || 'MyApp',
port: parseInt(process.env.APP_PORT) || 3000,
env: process.env.NODE_ENV || 'development'
},
database: {
url: process.env.DATABASE_URL,
poolSize: parseInt(process.env.DATABASE_POOL_SIZE) || 10
},
auth: {
jwtSecret: process.env.JWT_SECRET,
sessionSecret: process.env.SESSION_SECRET
}
};
module.exports = config;Python Example:
python
# config/settings.py
import os
from dotenv import load_dotenv
# Load environment variables
load_dotenv(f".env.{os.getenv('ENVIRONMENT', 'development')}")
class Config:
APP_NAME = os.getenv('APP_NAME', 'MyApp')
APP_PORT = int(os.getenv('APP_PORT', 5000))
DEBUG = os.getenv('DEBUG', 'false').lower() == 'true'
DATABASE_URL = os.getenv('DATABASE_URL')
REDIS_URL = os.getenv('REDIS_URL')
JWT_SECRET = os.getenv('JWT_SECRET')
API_KEY = os.getenv('API_KEY')Development Environment Setup
Local Development
Prerequisites
bash
# Install required tools
npm install -g node@18
pip install python@3.9
docker --version
git --versionProject Setup
bash
# Clone and setup project
git clone https://github.com/yourorg/project.git
cd project
# Copy environment template
cp .env.example .env.local
# Install dependencies
npm install
# or
pip install -r requirements.txt
# Setup database
npm run db:setup
# or
python manage.py migrate
# Start development server
npm run dev
# or
python manage.py runserverDocker Development
Docker Compose Setup
yaml
# docker-compose.dev.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp_dev
volumes:
- .:/app
- /app/node_modules
depends_on:
- db
- redis
db:
image: postgres:15
environment:
- POSTGRES_DB=myapp_dev
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7
ports:
- "6379:6379"
volumes:
postgres_data:Development Dockerfile
dockerfile
# Dockerfile.dev
FROM node:18-alpine
WORKDIR /app
# Install dependencies
COPY package*.json ./
RUN npm install
# Copy source code
COPY . .
# Expose port
EXPOSE 3000
# Start development server
CMD ["npm", "run", "dev"]Environment Validation
Schema Validation
Using Zod (TypeScript):
typescript
// config/env-schema.ts
import { z } from 'zod';
const envSchema = z.object({
NODE_ENV: z.enum(['development', 'staging', 'production', 'test']),
PORT: z.string().transform(Number).default('3000'),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
API_KEY: z.string().optional(),
DEBUG: z.string().transform(val => val === 'true').default('false')
});
export const env = envSchema.parse(process.env);Using Pydantic (Python):
python
# config/env_schema.py
from pydantic import BaseSettings, validator
from typing import Optional
class Settings(BaseSettings):
app_name: str = "MyApp"
debug: bool = False
database_url: str
jwt_secret: str
api_key: Optional[str] = None
@validator('jwt_secret')
def jwt_secret_must_be_long(cls, v):
if len(v) < 32:
raise ValueError('JWT secret must be at least 32 characters')
return v
class Config:
env_file = ".env"
settings = Settings()Security Best Practices
Secret Management
Never Commit Secrets
bash
# .gitignore
.env
.env.local
.env.*.local
*.key
*.pem
secrets/Use Secret Management Services
AWS Secrets Manager:
javascript
// utils/secrets.js
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();
async function getSecret(secretName) {
try {
const result = await secretsManager.getSecretValue({
SecretId: secretName
}).promise();
return JSON.parse(result.SecretString);
} catch (error) {
console.error('Error retrieving secret:', error);
throw error;
}
}HashiCorp Vault:
javascript
// utils/vault.js
const vault = require('node-vault')({
endpoint: process.env.VAULT_ENDPOINT,
token: process.env.VAULT_TOKEN
});
async function getVaultSecret(path) {
try {
const result = await vault.read(path);
return result.data;
} catch (error) {
console.error('Error reading from Vault:', error);
throw error;
}
}Environment Isolation
Network Isolation
yaml
# docker-compose.yml
version: '3.8'
services:
app:
networks:
- app-network
db:
networks:
- db-network
- app-network
networks:
app-network:
driver: bridge
db-network:
driver: bridge
internal: trueResource Limits
yaml
# docker-compose.yml
services:
app:
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256MCI/CD Integration
GitHub Actions
yaml
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main, staging]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set environment variables
run: |
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "ENVIRONMENT=production" >> $GITHUB_ENV
else
echo "ENVIRONMENT=staging" >> $GITHUB_ENV
fi
- name: Deploy to environment
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
run: |
echo "Deploying to $ENVIRONMENT"
# Deployment commands hereGitLab CI/CD
yaml
# .gitlab-ci.yml
stages:
- test
- deploy
variables:
DOCKER_DRIVER: overlay2
deploy_staging:
stage: deploy
environment:
name: staging
url: https://staging.myapp.com
variables:
ENVIRONMENT: staging
script:
- echo "Deploying to staging"
only:
- develop
deploy_production:
stage: deploy
environment:
name: production
url: https://myapp.com
variables:
ENVIRONMENT: production
script:
- echo "Deploying to production"
only:
- mainMonitoring and Logging
Environment-Specific Logging
javascript
// utils/logger.js
const winston = require('winston');
const logLevel = {
development: 'debug',
staging: 'info',
production: 'error'
}[process.env.NODE_ENV] || 'info';
const logger = winston.createLogger({
level: logLevel,
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({ stack: true }),
winston.format.json()
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'app.log' })
]
});
module.exports = logger;Health Checks
javascript
// routes/health.js
const express = require('express');
const router = express.Router();
router.get('/health', async (req, res) => {
const health = {
status: 'ok',
timestamp: new Date().toISOString(),
environment: process.env.NODE_ENV,
version: process.env.APP_VERSION,
checks: {
database: await checkDatabase(),
redis: await checkRedis(),
external_api: await checkExternalAPI()
}
};
const isHealthy = Object.values(health.checks).every(check => check.status === 'ok');
res.status(isHealthy ? 200 : 503).json(health);
});
module.exports = router;Troubleshooting
Common Issues
Environment Variables Not Loading
bash
# Check if .env file exists
ls -la .env*
# Verify environment variable loading
node -e "console.log(process.env.NODE_ENV)"
# Check for syntax errors in .env file
cat .env | grep -E '^[^#].*='Database Connection Issues
bash
# Test database connection
psql $DATABASE_URL -c "SELECT 1;"
# Check database logs
docker logs container_name
# Verify network connectivity
telnet db_host db_portPermission Issues
bash
# Fix file permissions
chmod 600 .env*
# Check Docker permissions
docker run --rm -v $(pwd):/app alpine ls -la /appDebugging Tools
javascript
// debug/env-check.js
console.log('Environment Check:');
console.log('NODE_ENV:', process.env.NODE_ENV);
console.log('Database URL:', process.env.DATABASE_URL ? 'Set' : 'Not set');
console.log('JWT Secret:', process.env.JWT_SECRET ? 'Set' : 'Not set');
console.log('All env vars:', Object.keys(process.env).filter(key => !key.startsWith('npm_')));Best Practices
Environment Management
- Use Environment Templates: Maintain
.env.examplewith all required variables - Validate Early: Validate environment variables at application startup
- Document Variables: Document the purpose and format of each variable
- Use Defaults: Provide sensible defaults for non-critical variables
- Separate Concerns: Keep different types of configuration separate
Security
- Never Commit Secrets: Use
.gitignoreto exclude sensitive files - Rotate Secrets: Regularly rotate API keys and passwords
- Principle of Least Privilege: Grant minimal necessary permissions
- Audit Access: Regularly audit who has access to production secrets
- Use Secret Management: Leverage dedicated secret management tools
Development Workflow
- Consistent Environments: Keep development and production environments similar
- Automated Setup: Provide scripts for easy environment setup
- Documentation: Maintain up-to-date setup documentation
- Testing: Test environment configurations in CI/CD pipelines
- Monitoring: Monitor environment health and performance