← writing

Terraform Best Practices: Environment Specific Resource Changes

·3 minawsterraform

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:

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:

HCL
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:

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

HCL
variable "enable_rds_multi_az" {
  type    = bool
  default = false
}

variable "enable_rds_deletion_protection" {
  type    = bool
  default = false
}

main.tf

HCL
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

TEXT
environments/
  dev/variables.tfvars
  prod/variables.tfvars

environments/dev/variables.tfvars

HCL
enable_rds_multi_az            = false
enable_rds_deletion_protection = false
TEXT
environments/prod/variables.tfvars
HCL
enable_rds_multi_az            = true
enable_rds_deletion_protection = true

Why this is better:

BASH
terraform apply -var-file=environments/dev/variables.tfvars

Folder Structure Recap

Here’s how your Terraform project should look:

TEXT
terraform-project/
├── main.tf
├── variables.tf
└── environments/
    ├── dev/
    │   └── variables.tfvars
    └── prod/
        └── variables.tfvars

Summary

When managing multiple environments in Terraform:

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.