DEV Community

Cover image for How Conditionals Make Terraform Infrastructure Dynamic and Efficient
Victor Robin
Victor Robin

Posted on

How Conditionals Make Terraform Infrastructure Dynamic and Efficient

If you are maintaining separate Terraform codebases for your Development, Staging, and Production environments, you are doing twice the work for half the reliability.

The gold standard of Infrastructure as Code is the Environment-Aware Module: a single, unified codebase that intelligently adapts its sizing, features, and resources based on the environment it is deployed into.

Today on my Terraform Challenge, I'll be diving deep into Terraform's conditional logic. Here is how Platform Teams use conditionals to eliminate code duplication and build smarter deployments.


1. The Ternary Operator & Environment-Aware Locals

The Problem: You want t3.micro instances in Dev to save money, but t3.small instances in Production to handle traffic. Scattering if/else logic directly inside your resource blocks makes your code incredibly difficult to read and update.

The Solution: Centralize your logic using the ternary operator (condition ? true_value : false_value) inside a locals block. This creates a single source of truth for your module's environment awareness.

[Image of Environment-aware Terraform module architecture]

Before (Hardcoded & Rigid):

resource "aws_instance" "web" {
  instance_type = var.instance_type # Requires passing this manually every time
}

Enter fullscreen mode Exit fullscreen mode

After (Dynamic & Centralized):


variable "environment" {
  description = "The deployment environment"
  type        = string
}


locals {
  # The boolean flag
  is_production = var.environment == "production"

  # Centralized environment sizing
  instance_type = local.is_production ? "t3.small" : "t3.micro"
  min_size      = local.is_production ? 3 : 1
}


resource "aws_instance" "web" {
  instance_type = local.instance_type # Clean, readable, and dynamic!
}
Enter fullscreen mode Exit fullscreen mode

2. The Optional Resource Pattern (count = condition ? 1 : 0)

The Problem: You need strict CloudWatch Alarms and Auto Scaling policies in Production, but deploying them in Dev is a waste of AWS budget. You cannot dynamically "comment out" a resource block.

The Solution: Use the count meta-argument as an On/Off switch. If the condition is true, Terraform sets the count to 1 (creates it). If false, it sets the count to 0 (skips it entirely).


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

resource "aws_autoscaling_policy" "scale_up" {
  # The On/Off Switch
  count = var.enable_scaling_policy ? 1 : 0

  name                   = "production-scale-up"
  autoscaling_group_name = aws_autoscaling_group.asg.name
  adjustment_type        = "ChangeInCapacity"
  scaling_adjustment     = 1
}

Enter fullscreen mode Exit fullscreen mode

3. Safely Referencing Conditionally Created Resources

The Problem: If you use the count = 0 trick above to skip creating a scaling policy, but your outputs.tf file still tries to export that policy's ARN, your terraform plan will crash. Terraform cannot output the ID of a resource that doesn't exist.

The Solution: You must reference conditionally created resources using the index [0] (since count treats them as a list), and use a ternary operator to output null if the resource was skipped.

Before (Will crash if count is 0):

output "scaling_policy_arn" {
  value = aws_autoscaling_policy.scale_up.arn
}
Enter fullscreen mode Exit fullscreen mode

After (Safe and robust):

output "scaling_policy_arn" {
  # If enabled, output the ARN of the first (and only) item. Otherwise, output null.
  value = var.enable_scaling_policy ? aws_autoscaling_policy.scale_up[0].arn : null
}
Enter fullscreen mode Exit fullscreen mode

4. Input Validation Blocks

The Problem: Your entire environment-aware module relies on the environment variable being exactly "dev", "staging", or "production". If a junior developer accidentally passes environment = "prod", your ternary conditionals will evaluate to false, deploying Dev-sized infrastructure into your Production AWS account.

The Solution: Use variable validation blocks. This forces Terraform to evaluate the input during the plan phase and immediately throw a custom error if the string isn't an exact match.

variable "environment" {
  description = "Deployment environment"
  type        = string

  validation {
    # The condition must evaluate to true, or the plan fails.
    condition     = contains(["dev", "staging", "production"], var.environment)
    error_message = "Fatal: Environment must be exactly 'dev', 'staging', or 'production'."
  }
}
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

Mastering conditionals transforms you from someone who writes Terraform scripts into someone who architects resilient cloud systems. By centralizing logic in locals, making resources toggleable, and validating inputs strictly, your modules become virtually bulletproof.

Are you using validation blocks in your Terraform modules yet? Let me know in the comments.

30DayTerraformChallenge #Terraform #IaC #DevOps #AWSUserGroupKenya #EveOps #CloudEngineering

Top comments (0)