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
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
}
}
How They Work
-
for_eachloops over a list or map - Terraform creates one nested block for each item
-
contentholds 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
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
}
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
Top comments (0)