DEV Community

Cover image for Day 10: Mastering Terraform Expressions - Conditional Logic, Iteration, and Collection
Tran Huynh An Duy (Andy)
Tran Huynh An Duy (Andy)

Posted on

Day 10: Mastering Terraform Expressions - Conditional Logic, Iteration, and Collection

This is Day 10, and we are diving deep into Terraform Expressions. Expressions are a fundamental concept, providing powerful, concise syntax that helps avoid rewriting code repeatedly. While similar in function to what we will later cover in Terraform functions, expressions offer immediate utility in making your configurations dynamic and reusable.
We focus today on three key expression types: Conditional, Dynamic Block, and Splat.

                ┌───────────────────────────────────────────┐
                │   Terraform Expressions                   │
                │   Simplify Configurations & Reduce Repetition │
                └───────────────────────────────────────────┘
                                │
   ┌────────────────────────────┼────────────────────────────┐
   │                            │                            │
   ▼                            ▼                            ▼
┌─────────────────┐      ┌────────────────────┐       ┌────────────────────┐
│ Conditional      │      │ Dynamic Blocks     │       │ Splat Expressions  │
│ Expressions      │      │ (nested iteration) │       │ (retrieve multiple │
│ (true/false logic)│     │                    │       │ attributes)        │
└─────────────────┘      └────────────────────┘       └────────────────────┘
   │                        │                            │
   ▼                        ▼                            ▼
┌─────────────────┐   ┌────────────────────┐       ┌────────────────────┐
│ Syntax:          │   │ Syntax:            │       │ Syntax:            │
│ condition ?      │   │ dynamic "block" {  │       │ resource.*.attr    │
│ true : false     │   │   for_each = list  │       │                    │
└─────────────────┘   │   content {...}     │       └────────────────────┘
                      └────────────────────┘
   │                        │                            │
   ▼                        ▼                            ▼
┌─────────────────┐   ┌────────────────────┐       ┌────────────────────┐
│ Example:         │   │ Example:           │       │ Example:           │
│ EC2 instance     │   │ Security Group     │       │ Collect EC2 IDs    │
│ type selection   │   │ ingress rules      │       │ into a list        │
└─────────────────┘   └────────────────────┘       └────────────────────┘


Enter fullscreen mode Exit fullscreen mode

1. Conditional Expressions: True or False Logic

A conditional expression is a simple, one-line piece of syntax that functions like an if/else statement found in most programming languages. It evaluates a condition and returns one of two specified values (the true value or the false value).

The Structure:
The conditional expression is always written as: condition ? true_value : false_value. The colon (:) separates the true value from the false value.

Code Example (Environment Selection):

This is most commonly used to set resource attributes based on environment variables. For instance, we can specify that if the environment is dev, a smaller instance type is used; otherwise, a larger one is selected.

variable "environment" {
  type    = string
  default = "staging" // Will select the false value
}

resource "aws_instance" "example" {
  // If var.environment == "dev" is TRUE, use T2 micro.
  // If FALSE (e.g., staging/prod), use T3 micro.
  instance_type = var.environment == "dev" ? "t2.micro" : "t3.micro" [4, 6]

  // ... other configuration ...
}
Enter fullscreen mode Exit fullscreen mode

As demonstrated in the demo, changing var.environment from dev to anything else (like staging or prod) immediately switches the instance type in the execution plan.

2. Dynamic Blocks: Nested Iteration

Dynamic blocks are essential when you need to write a nested block with multiple values within a resource definition. They help avoid manual repetition of configuration. This is frequently used for managing repeated elements, such as ingress or egress rules within an AWS Security Group.

The Structure and Iteration:

A dynamic block starts with the dynamic keyword, followed by a name (e.g., ingress). Inside, it uses a for_each argument to iterate over a collection (often a complex list of objects, like var.ingress_rules). The resource definitions must be placed within a content block.
When iterating, you access the attributes of the current element using the dynamic block name (e.g., ingress) and the special iterator object (value): ingress.value.from_port.

Code Example (Security Group Rules):

If we define two ingress rules (one for HTTP on port 80, one for HTTPS on port 443) in a list of objects variable, the dynamic block iterates through the list:

// Example Variable (List of Objects containing port, protocol, etc.) [8, 14]

resource "aws_security_group" "ingress_rule" {
  // ... other attributes ...

  dynamic "ingress" {
    for_each = var.ingress_rules // Iterates through the list of rules [11]

    content {
      from_port   = ingress.value.from_port [12] 
      to_port     = ingress.value.to_port [12]
      protocol    = ingress.value.protocol [12]
      cidr_blocks = ingress.value.cidr_blocks [12]
    }
  }
}
// This single block generates multiple ingress rules in the plan [15].
Enter fullscreen mode Exit fullscreen mode

3. Splat Expressions: Retrieving Multiple Attributes

The splat expression is another powerful one-liner used to retrieve a list of attributes from a set of resources. This is most useful when dealing with resources that were created using the count meta-argument, meaning they exist as a collection.
The splat expression uses the star operator ().
The Structure:
The expression is written as: resource_list.
.attribute.

Code Example (Collecting Instance IDs):

If we use count = 2 to create two EC2 instances (aws_instance.example), the splat expression retrieves the ID attribute for both instances and collects them into a list:

locals {
  // Collects the 'id' attribute from all instances named 'example'
  all_instance_ids = aws_instance.example.*.id [16-18]
}

output "instances" {
  value = local.all_instance_ids [19]
  // Value will be known after apply [19].
}
This efficiently creates a list containing [id_of_instance_0, id_of_instance_1].

Enter fullscreen mode Exit fullscreen mode

Mastering these expressions allows you to write truly dynamic and concise Infrastructure as Code. Make sure you complete the hands-on practice in the Day 10 GitHub repository to solidify your learning from @piyushsachdeva

Top comments (0)