Explain `for` expressions — how do you transform a list or map into another list or map?

5 minintermediateterraformfor-expressionshcl

Quick Answer

A for expression is HCL's list/map comprehension: [for s in var.subnets : s.id] transforms a list into a new list (here, extracting just the id from each object), while {for s in var.subnets : s.name => s.id} produces a map keyed by name. An optional if clause filters elements ([for s in var.subnets : s.id if s.public]), and wrapping the whole expression in {...} instead of [...] is what switches the result from a list to a map. for expressions are the standard way to reshape data pulled from one resource/variable into the exact shape another resource or a for_each needs.

Detailed Answer

for expressions are HCL's answer to "map over a list" or "build a dictionary from these elements." This is the kind of data reshaping that comes up constantly once you're passing computed values from one resource into another's for_each or a structured output.

List-to-list

variable "subnets" {
  type = list(object({
    id     = string
    public = bool
  }))
}

locals {
  subnet_ids = [for s in var.subnets : s.id]
  # -> ["subnet-aaa", "subnet-bbb", "subnet-ccc"]
}

Square brackets ([...]) produce a list, with one output element per input element (unless filtered out).

List-to-map

locals {
  subnets_by_id = {for s in var.subnets : s.id => s}
  # -> { "subnet-aaa" = {...}, "subnet-bbb" = {...}, ... }
}

Curly braces ({...}) with a key => value pair instead produce a map. This single syntax change ([...] vs {...}) is what determines whether you get a list or a map out.

Filtering with if

locals {
  public_subnet_ids = [for s in var.subnets : s.id if s.public]
}

The optional trailing if clause skips elements that don't satisfy the condition — here, only including subnets where public == true.

Iterating over maps

locals {
  # var.tags is a map(string)
  tag_list = [for k, v in var.tags : "${k}=${v}"]
}

When iterating a map, for k, v in ... gives you both the key and value per iteration.

Why this matters practically

for expressions are the standard glue between resources: turning a list of objects a data source returned into the exact map shape a for_each needs, or reshaping a module's raw output into something a consuming resource can use directly. No imperative loop code is needed, since HCL has no for statement, only this expression form.

Related Resources