When managing infrastructure with Terraform, it’s common to have multiple environments such as development (dev), staging, and production (prod).
Each environment usually requires slightly different configurations, for example enabling resilience features in production while keeping development simple and cost efficient.
A common mistake teams make is to dynamically control resource behavior based on the current environment name. This leads to hard to read code and increases the risk of misconfiguration.
In this article, we’ll explore:
- Why this approach is problematic.
- A better, scalable solution using explicit variables and environment-specific
tfvars
files. - Practical examples for both bad and good implementations.
Example Scenario
Let’s say you are creating an RDS instance.
In production, you want to enable Multi-AZ for high availability and Deletion Protection to avoid accidental data loss.
In development, you do not need those features because it is cheaper and easier to tear down resources.
Let’s see how this can be implemented.
Bad Way: Inline Environment Conditions
Some teams try to control behavior directly using the environment name:
variable "environment" {
description = "The environment (dev, stg, prod)"
type = string
}
variable "environment" {
type = string
}
resource "aws_db_instance" "example" {
allocated_storage = 20
engine = "mysql"
instance_class = "db.t3.micro"
username = "admin"
password = "supersecret"
skip_final_snapshot = true
# ❌ Logic buried in conditions
multi_az = var.environment == "prod" ? true : false
deletion_protection = var.environment == "prod" ? true : false
}
Why this is bad:
- ❌ Hidden logic – It’s unclear what is enabled for each environment without reading through the code.
- ❌ Risky changes – Adding a new environment might require modifying multiple conditions across files.
- ❌ Harder reviews – Code reviewers must mentally evaluate conditions for each environment.
- ❌ Not scalable – Complex conditions can quickly get out of hand.
Good Way: Explicit Variables
Instead of relying on the environment name inside your code, declare explicit variables for each toggle and set their values in environment specific tfvars
files.
variables.tf
variable "enable_rds_multi_az" {
type = bool
default = false
}
variable "enable_rds_deletion_protection" {
type = bool
default = false
}
main.tf
resource "aws_db_instance" "main" {
allocated_storage = 20
engine = "mysql"
instance_class = "db.t3.micro"
username = "admin"
password = "supersecret"
skip_final_snapshot = true
# ✅ Explicit, environment-specific toggles
multi_az = var.enable_rds_multi_az
deletion_protection = var.enable_rds_deletion_protection
}
Environment Specific Variables
environments/
dev/variables.tfvars
prod/variables.tfvars
environments/dev/variables.tfvars
enable_rds_multi_az = false
enable_rds_deletion_protection = false
environments/prod/variables.tfvars
enable_rds_multi_az = true
enable_rds_deletion_protection = true
Why this is better:
- ✅ Clear and explicit – It’s immediately obvious which environments have Multi-AZ and Deletion Protection enabled by checking the
tfvars
files. - ✅ Simpler deployments – Each environment just passes its own
tfvars
file:
terraform apply -var-file=environments/dev/variables.tfvars
- ✅ Safe scaling – Adding a new environment is as simple as creating a new
tfvars
file, no code changes needed. - ✅ Easier reviews – Reviewers only need to check the variable value, not Terraform logic.
Folder Structure Recap
Here’s how your Terraform project should look:
terraform-project/
├── main.tf
├── variables.tf
└── environments/
├── dev/
│ └── variables.tfvars
└── prod/
└── variables.tfvars
Summary
When managing multiple environments in Terraform:
- Avoid inline conditions like
if environment == "prod"
- Use explicit variables to control environment specific features
- Keep environment differences in
tfvars
files, not in the Terraform code
This approach keeps your infrastructure code clean, predictable, and scalable. It ensures safer deployments and simpler reviews.
Always prefer explicit toggles over hidden conditions. This makes your Terraform code safer, easier to review, and more predictable as your environments grow.
Leave a Reply