Environment Parity
Overview
Environment parity means using the same infrastructure code across all environments, with only configuration values changing. This reduces "works on my machine" problems and ensures production behavior is tested before deployment.
mermaid
graph LR
subgraph "Single Codebase"
Code[Infrastructure Code]
end
subgraph "Configurations"
Dev[dev.tfvars]
Staging[staging.tfvars]
Prod[prod.tfvars]
end
subgraph "Environments"
DevEnv[Development]
StagingEnv[Staging]
ProdEnv[Production]
end
Code --> Dev --> DevEnv
Code --> Staging --> StagingEnv
Code --> Prod --> ProdEnv
What Should Differ
| Configuration | Dev | Staging | Prod |
|---|---|---|---|
| Instance sizes | t3.small | t3.medium | t3.large |
| Replica count | 0 | 1 | 2 |
| Multi-AZ | false | false | true |
| Deletion protection | false | false | true |
| Backup retention | 1 day | 7 days | 30 days |
| Monitoring | basic | enhanced | enhanced |
What Should NOT Differ
- •✅ Resource types and structure
- •✅ Security group rules (ports, protocols)
- •✅ IAM policy structure
- •✅ Encryption settings
- •✅ Network topology
Best Practices
- •Single source of truth - One codebase, multiple configs
- •Use tfvars/context - Environment-specific settings
- •Conditional logic sparingly - Prefer configuration over conditionals
- •Match production - Staging should mirror prod closely
- •Test in lower environments first - Dev → Staging → Prod
Example 1: Terraform - Workspaces + Variable Files
Environment parity with workspace isolation and tfvars files.
📁 Location: terraform/examples/environment-parity/
Configuration Files
hcl
# environments/dev.tfvars environment = "dev" instance_type = "t3.small" rds_instance_class = "db.t3.micro" rds_multi_az = false rds_deletion_protection = false min_capacity = 1 max_capacity = 2 enable_enhanced_monitoring = false
hcl
# environments/prod.tfvars environment = "prod" instance_type = "t3.large" rds_instance_class = "db.r5.large" rds_multi_az = true rds_deletion_protection = true min_capacity = 3 max_capacity = 10 enable_enhanced_monitoring = true
Usage
bash
# Deploy to dev terraform workspace select dev terraform apply -var-file="environments/dev.tfvars" # Deploy to prod terraform workspace select prod terraform apply -var-file="environments/prod.tfvars"
Example 2: CDK - Context-Based Configuration
Environment parity using CDK context for configuration.
📁 Location: cdk/examples/environment-parity/
Context Configuration
typescript
// cdk.json
{
"context": {
"dev": {
"instanceType": "t3.small",
"rdsInstanceClass": "db.t3.micro",
"multiAz": false,
"minCapacity": 1,
"maxCapacity": 2
},
"prod": {
"instanceType": "t3.large",
"rdsInstanceClass": "db.r5.large",
"multiAz": true,
"minCapacity": 3,
"maxCapacity": 10
}
}
}
// app.ts
const environment = app.node.tryGetContext('environment') || 'dev';
const config = app.node.tryGetContext(environment);
new MyStack(app, `MyApp-${environment}`, {
...config,
environment,
});
Usage
bash
# Deploy to dev cdk deploy --context environment=dev # Deploy to prod cdk deploy --context environment=prod
Validation Checklist
- • Same Terraform/CDK code deploys to all environments
- • Only configuration values differ (sizes, counts, retention)
- • Security configurations are consistent
- • Staging closely matches production
- • Changes tested in dev/staging before prod
Related Skills
- •Layered Stacks - Layers per environment
- •GitOps Workflow - Environment promotion
- •Remote State Boundaries - State per env