How to iterate over a map in Terraform

Updated: February 4, 2024 By: Guest Contributor Post a comment

Introduction

In Terraform, managing infrastructure often requires handling collections of resources. One common structure you’ll encounter is a map, an associative array containing key-value pairs. This guide will walk you through several methods to iterate over a map in Terraform, ranging from basic examples to more advanced use cases, demonstrating how Terraform’s loop constructs can be leveraged effectively.

Understanding Maps in Terraform

Before diving into iteration, it’s essential to understand what maps are in Terraform. A map is a data structure that matches keys to values, providing a way to group related data. In Terraform, you typically use maps to configure resources with similar settings that have slight variations.

variable "instance_details" {
  type = map(object({
    zone     = string
    size     = string
  }))
  default = {
    "instance1" = { zone = "us-west-1a", size = "t2.micro" },
    "instance2" = { zone = "us-west-1b", size = "t2.small" }
  }
}

This example defines a map of objects, where each key-value pair represents the details of a virtual machine.

Basic Iteration with count

One of the simplest ways to iterate over a map in Terraform is using the count parameter within a resource declaration. This method is especially useful for creating multiple instances of a resource.

resource "aws_instance" "example" {
  count         = length(var.instance_details)
  ami           = "ami-123456"
  instance_type = var.instance_details[keys(var.instance_details)[count.index]].size
  availability_zone = var.instance_details[keys(var.instance_details)[count.index]].zone
}

This snippet creates AWS instances based on the map’s values, iterating through the map using a combination of length, keys, and the count.index loop variable.

Advanced Iteration with for_each

Terraform 0.12 introduced the for_each statement, a more powerful iteration tool that iterates directly over maps and collections. It’s particularly useful when you want to create resources for each element in a map and maintain a clear relationship between the created resources and the map’s keys.

resource "aws_instance" "example" {
  for_each      = var.instance_details
  ami           = "ami-123456"
  instance_type = each.value.size
  availability_zone = each.value.zone
  tags = {
      Name = each.key
  }
}

This example uses for_each to iterate over the map, creating a unique AWS instance for each key-value pair. The each.key and each.value constructs provide access to the current element’s key and value, respectively.

Combining Maps with Dynamic Blocks

Dynamic blocks are a feature in Terraform that allows for the dynamic creation of nested blocks based on a complex variable, such as a map or list. When used in conjunction with for_each, dynamic blocks can efficiently configure resources that require repeated nested configurations.

resource "aws_security_group" "example" {
  name = "example-group"

  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
    }
  }
}

This code snippet defines a security group in AWS, where the ingress rules are dynamically generated from a map of ingress configurations.

Conditional Iteration

There are scenarios where you might wish to iterate over a map conditionally. This can be achieved by combining for_each with a filtering step using a splat expression or compact function.

locals {
  filtered_instance_details = { for k, v in var.instance_details : k => v if v.zone == "us-west-1a" }
}

resource "aws_instance" "filtered_example" {
  for_each      = local.filtered_instance_details
  ami           = "ami-123456"
  instance_type = each.value.size
  availability_zone = each.value.zone
}

This demonstrates filtering a map to iterate only over items that meet specific conditions, in this case, instances in the “us-west-1a” zone.

Conclusion

In Terraform, iterating over maps is a foundational skill that enables scalable and flexible infrastructure configurations. Starting with basic techniques like using count and advancing to for_each and dynamic blocks, Terraform provides a range of tools for efficiently managing infrastructure with complex configurations. By mastering these techniques, you can streamline your Terraform code and embrace infrastructure as code principles more fully.