count and for_each. While count and for_each control how many resources Terraform creates, for expressions are used to reshape or derive new data structures (lists, sets, maps, strings) from existing inputs. Think of them as a preprocessing step: transform the input data with a for expression, then feed the result into for_each, module inputs, or other resource arguments.
Below is a compact example followed by a step‑by‑step explanation.
For expressions only produce data—they do not create resources. Use them to prepare or reshape values (lists, sets, maps, strings) that you then pass into
for_each, resource arguments, modules, or other expressions. They keep configurations DRY and easier to maintain.- variable block
variable "environments"defines a simple list:["prod", "dev", "test"]. These are input values only; no resources are created here.
- locals block and the for expression
resource_group_names = [for env in var.environments : "rg-${env}"]- This iterates each element in
var.environments, transforms the value by prefixingrg-, and produces a new list:["rg-prod", "rg-dev", "rg-test"].
- resource block and
for_eachfor_each = toset(local.resource_group_names)converts the list into a set.for_eachrequires either a set or a map (not a plain list). Converting to a set ensures uniqueness and establishes stable keys that Terraform uses to track resources between runs.- Inside the resource block,
each.valuerepresents the current element from the collection (here, the resource group name) and is used as thename.
- DRY configuration: Add or remove environment names in a single place and derived values update automatically.
- Flexible transformations: Build formatted names, filter elements, or generate complex maps used later in resources or modules.
- Separation of concerns: Locals act as a preprocessing layer—shape inputs exactly the way resources expect them.
- For expressions return a collection type (list, set, or map) depending on the syntax and context; they do not create resources.
- Use
toset()ortomap()when required by consumers likefor_eachso Terraform can use stable keys to track resources across runs. - When using a map with
for_each, the map keys become resource instance keys andeach.valueis the corresponding value. For sets of primitive values, the element itself becomes the stable identifier used byfor_each.
Do not pass a plain list directly into
for_each. Always convert lists into toset() or build a map to ensure deterministic resource keys and avoid unexpected resource recreation.
When to use for expressions
- Any time you need to prepare or transform input data before passing it into
for_each, module inputs, or resource arguments. - Useful for consistent naming, filtering unwanted elements, or composing more complex structures from simple variables.
- For expressions transform data structures—they do not create resources.
- Locals commonly host for expressions to prepare data for resource creation.
for_eachconsumes transformed data (often after conversion to a set or map), and resources are created based on those values.
- Terraform documentation: For expressions
- Terraform documentation: for_each meta-argument
- Terraform locals documentation