Elevate Your Terraform Game by leveraging for loops in Terraform

A guide to map transformation using for loops in Terraform.

Akhilesh Mishra
4 min readAug 28, 2023

With a for loop, you can iterate through the keys and values of a map, applying custom logic to each element.

This logic can involve filtering out certain elements, generating new keys or values, and creating entirely new maps based on the original data.

In this blog post, we’re diving deep into the art of map transformation using the powerful for-loop construct.

Photo by Ari He on Unsplash

Map Transformation in Terraform

When you want to create a new map that’s based on an existing map but with slight modifications to the values or keys. This can be useful for creating variations of configurations.

Map transformation using for loops enhances code readability, maintainability, and flexibility in your Terraform configurations.

Use cases of map transformation in Terraform

  • Copying Maps: If you want to duplicate or clone a map, maintain the same keys and values. This can help in creating independent instances of a configuration.
locals {
original_map = {
key1 = "value1"
key2 = "value2"
key3 = "value3"
}

cloned_map = { for k, v in local.original_map : k => v }
}
  • Map Filtering: You can filter out certain elements from a map based on certain conditions, creating a new map with only the elements that meet the criteria.
locals {
original_map = {
apple = 5
banana = 3
orange = 7
pear = 2
}

filtered_map = { for k, v in local.original_map : k => v if v > 3 }
}
  • Map Subsetting: When you want to create a smaller map that contains a subset of the original keys and values, potentially to pass to a module or resource.
locals {
full_map = {
a = 1
b = 2
c = 3
d = 4
}

subset_map_keys = ["a", "c"]

subset_map = { for k, v in local.full_map : k => v if k in local.subset_map_keys }
}
  • Data Transformation: Converting data formats or structures into a different format, often used in data processing or preparation tasks.
locals {
raw_data = {
"name": "John Doe",
"age": 30,
"location": "City"
}

transformed_data = {
for key, value in local.raw_data :
key == "name" ? "full_name" :
key == "age" ? "years_old" :
key == "location" ? "city" : key => value
}
}
  • Generating Inputs: Generating input variables or configuration settings for resources or modules based on an existing map of data.
locals {
resource_settings = {
"web" = { port = 80, protocol = "http" }
"db" = { port = 3306, protocol = "mysql" }
}

resource_instances = flatten([
for name, settings in local.resource_settings : [
for i in range(2) : {
name = "${name}-${i}"
port = settings.port
protocol = settings.protocol
}
]
])
}
  • Creating Labels or Tags: When you need to create labels or tags for resources based on predefined keys and values.
locals {
resource_names = ["instance1", "instance2", "instance3"]

resource_labels = {
for name in local.resource_names : name => "tag-${name}"
}
}
  • Configuration Composition: When you want to create complex configurations by combining multiple simpler configurations using maps.
locals {
base_config = {
region = "us-west-1"
environment = "production"
}

module_overrides = {
instance1 = {
region = "us-east-1"
instance_type = "t2.micro"
}
instance2 = {
environment = "development"
instance_type = "t2.nano"
}
}

final_config = {
for name, config in local.module_overrides : name => merge(local.base_config, config)
}
}

These examples should give you a solid foundation for understanding how to perform various map transformations using for loops in Terraform.

Remember that the key strength of this loop construct is its ability to efficiently create new maps that maintain the original structure.

The same for-loop construct can be used for List comprehension as well. Let's take a few examples of that

  • If you want to create a list of keys, or values from a map.
locals {
aws_bucket_names = {
"name1" = "bucket1",
"name2" = "bucket2",
"name3" = "bucket3"
}

bucket_name_list = [for name, _ in local.aws_bucket_names : name]
}

output "bucket_names" {
value = local.bucket_name_list
}
  • Case conversion
[for s in var.list : upper(s)]
  • A for expression can also include an optional if clause to filter elements from the source collection, producing a value with fewer elements than the source value:
[for s in var.list : upper(s) if s != ""]

There can be an infinite number of use cases that you can leverage to write flexible IAC code that is more readable, and scalable. This blog post is originally published on my blog — Livingdevops.com

If you enjoyed the writings leave your claps 👏 to recommend this article so that others can see it

Also, read

Thanks for reading. See you on the next one!

--

--

Akhilesh Mishra

Self taught DevOps engineer with expertise in multi-cloud, and various DevOps tools. Open for mentorship - https://topmate.io/akhilesh_mishra