Terraform Associate: Create Dynamic Expressions

Table of contents
- 1. Using Variables in Expressions
- 2. Conditional Expressions (? :)
- 3. Using for_each for Dynamic Resource Creation
- 4. Using count for Dynamic Scaling
- 5. Dynamic Block Configuration with for_each
- 6. Using lookup() for Dynamic Map Values
- 7. Combining Expressions for Advanced Logic
- 8. Best Practices for Dynamic Expressions
- Conclusion
- Reference

Terraform’s power goes beyond merely defining static resources—its dynamic expressions empower you to build flexible, scalable, and maintainable infrastructure as code. By leveraging variables, functions, conditionals, loops, and lookups, you can generate dynamic values for your resources, streamlining your configurations and reducing the need for repetitive hardcoding.
In this guide, we’ll explore various dynamic expression techniques in Terraform with practical examples and best practices to help you create adaptable and efficient infrastructure configurations.
1. Using Variables in Expressions
Input variables allow you to inject dynamic values into your resources. For instance, you can conditionally set an EC2 instance type based on the environment.
Example: Dynamic EC2 Instance Type Based on Environment
variable "environment" {
type = string
default = "dev"
}
resource "aws_instance" "web" {
ami = "ami-12345678"
instance_type = var.environment == "prod" ? "t3.large" : "t3.micro"
}
- Explanation:
If theenvironment
is set to"prod"
, Terraform uses a larger instance type (t3.large
); otherwise, it defaults to a smaller type (t3.micro
). This simple conditional makes it easy to adapt resources based on deployment context.
2. Conditional Expressions (? :
)
Conditional expressions provide if-else logic within your configuration, allowing you to dynamically assign values based on conditions.
Example: Assigning Storage Size Based on Environment
variable "env" {
default = "dev"
}
resource "aws_instance" "server" {
ami = "ami-12345678"
instance_type = "t3.micro"
root_block_device {
volume_size = var.env == "prod" ? 100 : 50
}
}
- Explanation:
Here, the root block device's volume size is set to 100GB for a production environment and 50GB for development, ensuring that resources are appropriately sized for different environments.
3. Using for_each
for Dynamic Resource Creation
The for_each
loop allows you to create multiple resources dynamically based on a collection of values.
Example: Create Multiple S3 Buckets
variable "bucket_names" {
type = list(string)
default = ["bucket1", "bucket2", "bucket3"]
}
resource "aws_s3_bucket" "example" {
for_each = toset(var.bucket_names)
bucket = each.value
}
- Explanation:
Withfor_each
, Terraform iterates over the list of bucket names and creates an S3 bucket for each item. This approach is ideal when you need to manage a variable number of similar resources.
4. Using count
for Dynamic Scaling
When you need to create several instances of the same resource, the count
parameter can be used for dynamic scaling.
Example: Create Multiple EC2 Instances
variable "instance_count" {
default = 3
}
resource "aws_instance" "web" {
count = var.instance_count
ami = "ami-12345678"
instance_type = "t3.micro"
}
- Explanation:
Thecount
parameter instructs Terraform to create three EC2 instances wheninstance_count
is set to 3, simplifying the process of scaling out your infrastructure.
5. Dynamic Block Configuration with for_each
For resources with nested blocks that require dynamic configuration, the dynamic
block allows you to iterate over collections to generate nested blocks.
Example: Dynamic Security Group Rules
variable "ingress_rules" {
type = list(object({
port = number
cidr_blocks = list(string)
}))
default = [
{ port = 80, cidr_blocks = ["0.0.0.0/0"] },
{ port = 443, cidr_blocks = ["0.0.0.0/0"] }
]
}
resource "aws_security_group" "web" {
name = "web-sg"
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = "tcp"
cidr_blocks = ingress.value.cidr_blocks
}
}
}
- Explanation:
This configuration dynamically creates multiple ingress rules for the security group based on the provided list. It’s an efficient way to manage nested configurations that vary in quantity or content.
6. Using lookup()
for Dynamic Map Values
The lookup()
function retrieves values from a map dynamically, providing a default value if the key does not exist.
Example: Select an AMI Based on Region
variable "region" {
default = "us-east-1"
}
variable "ami_map" {
default = {
"us-east-1" = "ami-12345678"
"us-west-2" = "ami-87654321"
}
}
resource "aws_instance" "web" {
ami = lookup(var.ami_map, var.region, "ami-default")
instance_type = "t3.micro"
}
- Explanation:
Thelookup()
function checksvar.ami_map
for the key corresponding to the region. If found, it returns the associated AMI; otherwise, it defaults to"ami-default"
. This is particularly useful for multi-region deployments.
7. Combining Expressions for Advanced Logic
You can combine multiple expressions to implement more sophisticated decision-making logic.
Example: Select a Value Based on Multiple Conditions
variable "env" {
default = "dev"
}
variable "instance_map" {
default = {
"dev" = "t3.micro"
"test" = "t3.medium"
"prod" = "t3.large"
}
}
resource "aws_instance" "server" {
instance_type = lookup(var.instance_map, var.env, "t2.micro")
}
- Explanation:
This example combines a variable and a lookup function to choose an appropriate EC2 instance type based on the environment. If the environment isn’t defined in the map, it defaults to"t2.micro"
.
8. Best Practices for Dynamic Expressions
To maximize the benefits of dynamic expressions in Terraform, consider these best practices:
Use
count
for Identical Resources:
When creating multiple instances of the same resource, usecount
to keep your code concise.Prefer
for_each
for Unique Items:
Usefor_each
when each resource instance is unique or when iterating over a collection with distinct keys.Simplify with Conditionals:
Leverage conditional expressions (? :
) to make environment-based decisions clear and concise.Utilize
lookup()
to Avoid Hardcoding:
Dynamic map lookups help maintain flexibility and reduce hardcoded values in your configurations.Employ Dynamic Blocks:
Use dynamic blocks for nested configurations that need to adjust based on input variables or other dynamic data.
Conclusion
Dynamic expressions in Terraform enable you to build adaptable, reusable, and efficient infrastructure configurations. By integrating variables, conditionals, loops, and lookups into your code, you can cater to varying deployment scenarios without rewriting or duplicating configurations. Embracing these techniques not only simplifies your code but also ensures that your infrastructure scales gracefully as requirements change.
Happy coding and automating with Terraform!
Reference
Terraform Expressions Documentation
https://www.terraform.io/language/expressions
Detailed guidance on writing dynamic expressions in Terraform to generate flexible configurations.Terraform Conditional Expressions
https://www.terraform.io/language/expressions/conditionals
Learn how to implement if-else logic within your Terraform configurations to adapt resource definitions dynamically.Terraform Meta-Arguments: for_each and count
https://www.terraform.io/language/meta-arguments/for_each
Explains how to dynamically create multiple resources using the for_each and count meta-arguments.Dynamic Blocks in Terraform
https://www.terraform.io/language/expressions/dynamic-blocks
Explore how to generate nested blocks dynamically to manage complex resource configurations.Terraform Best Practices
https://learn.hashicorp.com/tutorials/terraform/best-practices
A comprehensive tutorial on writing maintainable and efficient Terraform code, including strategies for dynamic expressions.
Subscribe to my newsletter
Read articles from Chintan Boghara directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Chintan Boghara
Chintan Boghara
Exploring DevOps ♾️, Cloud Computing ☁️, DevSecOps 🔒, Site Reliability Engineering ⚙️, Platform Engineering 🛠️, Machine Learning Operations 🤖, and AIOps 🧠