DEV Community

Cover image for Terraform Expressions — Conditional, Dynamic & Splat Expressions
Adarsh Gupta
Adarsh Gupta

Posted on

Terraform Expressions — Conditional, Dynamic & Splat Expressions

Introduction

Terraform provides a powerful configuration language that allows you to build reusable, scalable, and environment-aware infrastructure. Three of the most useful features within Terraform’s expression system are conditional expressions, dynamic blocks, and splat expressions.

Understanding these three concepts helps you write cleaner, more flexible code while avoiding duplication and complexity. This blog explains each expression in detail, including when to use them, when not to use them, and how they work together.


Conditional Expressions

What They Are

Conditional expressions return one of two values depending on whether a given condition is true or false.

Syntax

condition ? true_value : false_value
Enter fullscreen mode Exit fullscreen mode

How They Work

  • If the condition is true, the first value is returned.
  • If the condition is false, the second value is returned.
  • Similar to ternary operators in traditional programming languages.

Use Cases

  • Switching instance types based on environment
  • Enabling or disabling optional features
  • Selecting AMIs per region
  • Setting resource counts dynamically
  • Applying environment-specific tags

Benefits

  • Reduces code duplication
  • Makes environment differences explicit
  • Allows a single configuration to serve multiple use cases

When to Use

  • Feature toggles
  • Environment-based settings
  • Conditional resource attributes

When Not to Use

  • When logic becomes too complex
  • When separate configuration files would be clearer
  • When the same behavior is required in all environments

Dynamic Blocks

What They Are

Dynamic blocks allow you to programmatically generate nested blocks inside Terraform resources. They are useful when a resource needs multiple similar nested configurations.

Syntax

dynamic "block_name" {
  for_each = var.collection
  content {
    # content for each generated block
  }
}
Enter fullscreen mode Exit fullscreen mode

How They Work

  • for_each loops over a list or map
  • Terraform creates one nested block for each item
  • content holds the fields of the nested block

Use Cases

  • Multiple ingress/egress rules in security groups
  • Multiple EBS volumes
  • Multiple IAM policy statements
  • Listener rules in load balancers
  • Route table routes

Benefits

  • Eliminates repetitive blocks
  • Driven by variables for better flexibility
  • Produces cleaner, maintainable configurations

When to Use

  • When nested blocks repeat
  • When the number of blocks should be dynamic
  • When variables drive configuration

When Not to Use

  • When only one or two static blocks are needed
  • When readability decreases
  • For top-level resources

Best Practices

  • Use descriptive iterator names
  • Avoid deep nesting
  • Document expected data structures

Splat Expressions

What They Are

Splat expressions extract a specific attribute from every element in a list using the [*] operator.

Syntax

resource_list[*].attribute_name
Enter fullscreen mode Exit fullscreen mode

How They Work

  • Works on lists of objects or resources
  • Returns a list containing only the selected attribute

Use Cases

  • Collecting instance IDs
  • Gathering private or public IPs
  • Extracting security group IDs
  • Producing lists of subnets or ARNs
  • Simplifying outputs from multiple instances

Benefits

  • Very concise
  • Easy extraction of repeated attributes
  • Ideal for resources created using count

Limitations

  • Works only with lists or sets
  • For maps, a different expression is needed
  • Empty lists produce empty outputs—must be handled upstream

Example Using All Three Expressions

variable "environment" {
  type    = string
  default = "dev"
}

variable "ingress_rules" {
  type = list(object({
    from_port   = number
    to_port     = number
    protocol    = string
    cidr_blocks = list(string)
  }))

  default = [
    { from_port = 80,  to_port = 80,  protocol = "tcp", cidr_blocks = ["0.0.0.0/0"] },
    { from_port = 443, to_port = 443, protocol = "tcp", cidr_blocks = ["0.0.0.0/0"] }
  ]
}

resource "aws_security_group" "web_sg" {
  name = "web-sg-${var.environment}"

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.from_port
      to_port     = ingress.value.to_port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }

  description = var.environment == "prod" ? "Production SG" : "Development SG"
}

resource "aws_instance" "web" {
  count         = var.environment == "prod" ? 3 : 1
  ami           = "ami-xxxxxxxx"
  instance_type = var.environment == "prod" ? "t3.medium" : "t3.micro"

  vpc_security_group_ids = [aws_security_group.web_sg.id]
}

output "instance_ids" {
  value = aws_instance.web[*].id
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Conditional expressions, dynamic blocks, and splat expressions are foundational tools for writing flexible, modular, and reusable Terraform code. Correct use of these features helps you:

  • Reduce redundancy
  • Manage infrastructure across multiple environments
  • Maintain cleaner, more scalable configurations

Mastering these expressions greatly enhances your Terraform workflow and prepares you for larger, more complex infrastructure projects.


Embedded Video

@piyushsachdeva

Top comments (0)