For Expression

A for expression is a way to transform one complex type value, such as a list, tuple, or object, into another complex type value. It achieves this transformation through a three-step process:
The syntax of a for expression is:
for i <complex-type> : <expression> if <condition>
Here is the breakdown of syntax:
Suppose you have a list of user objects, and you want to create a new list which contains only the usernames. You could use a for expression to transform the list of user objects into a list of usernames:
variable "users" {
    default = [
        {
            username = "ajay"
            age = 22
        },
        {
            username = "banar"
            age = 26
        },
        {
            username = "raja"
            age = 22
        }
    ]
}
output "tranformed-var" {
    value = [for i in var.os : i.username]
}
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
tranformed-var = [
    "ajay",
    "banar",
    "raja",
]
In this example, var.users is an input list, and the transformation expression is i.username, which is used to extract a username from each user object. The result will be a new list that contains only usernames.

Input Types

Input types for a For Expression in Terraform can be one of list, set, tuple, map, or object. The for expression has one or two temporary symbols:

1. Single temporary symbol:

In a For Expression, a single temporary symbol consists of single variable that represents the value of each element in the input collection. This type of symbol can be used with lists, sets, and tuples. When you use a single temporary symbol within a For Expression, Terraform assigns the value of each element in the input collection to that symbol. Then, you can use that symbol to change or manipulate the value in some way. Example
variable "list" {
    default = [1,2,3,4]
}
output "tranformed-var" {
    value = [for i in var.list : tostring(i)]
}
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
tranformed-var = [
    "1",
    "2",
    "3",
    "4",
]
In the above example, the single temporary symbol, i represents the value of each element in the list input collection.

2. Pair of temporary symbols:

In a For Expression, a pair of temporary symbols consists of two variables that represent two different aspects of each element in the input collection. First symbol represents the key/index of the element while the second symbol represents the value of the element. This type of symbol can be used on several input collections such as list, set, tuple, map, and object.
When the input collection is a list, set, or tuple, the first symbol i or idx represents the index of each element, starting from 0 and the second symbol v represents the value of each element.
variable "list" {
    default = [1,2,3,4]
}
output "tranformed-var" {
    value = {for i,v in var.list : i => tostring(v)}
}
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
tranformed-var = [
    "0" = "1",
    "1" = "2",
    "2" = "3",
    "3" = "4",
]
When the input collection is a map or an object, then the first symbol k represents the key or attribute name of the current element and The second symbol v represents the value of each element in the collection.
variable "list" {
    default = {
        a = 1
        b = 2
        c = 3
        d = 4
    }
}
output "tranformed-var" {
    value = {for i,v in var.map : i => tostring(v)}
}
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
tranformed-var = {
    "a" = "1",
    "b" = "2",
    "c" = "3",
    "d" = "4"
}

Result Types

The For Expression in Terraform has two possible result types: tuples (lists) and objects (maps). The type of brackets used defines the result type:
variable "fruits" {
    default = ["apple", "banana", "cherry"]
}
output "uppercase_fruits" {
    value = [for fruit in var.fruits : upper(fruit)]
}
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
uppercase_fruits = [
    "APPLE",
    "BANANA",
    "CHERRY",
]
In this example, the For Expression is using square brackets [ ] to return a tuple, or list, result. The result will be a list of fruit names in all uppercase, where each value has an index.
variable "fruits" {
    default = ["apple", "banana", "cherry"]
}
output "uppercase_fruits" {
    value = { for fruit in var.fruits : fruit => upper(fruit) }
}
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
uppercase_fruits = {
   "apple" = "APPLE",
   "banana" = "BANANA",
   "cherry" = "CHERRY",
}
This example uses curly braces { } in the For Expression to produce an object (map) result. The result of this expression will be an object whose keys are names of fruit and values are their capital cases.
NOTE: Although for expressions can only produce tuple or object values, Terraform's automatic type conversion rules allow you to use these results in locations that expect lists, maps, and sets.

Filtering Elements in For Expressions

You can add an optional if clause to a for expression in order to filter out certain elements from the source collection. This will produce a result with fewer elements than the original collection.
variable "fruits" {
    type = list(string)
    default = ["apple", "banana", "", "orange", "", "grape"]
}
output "non_empty_fruits" {
    value = [for fruit in var.fruits : fruit if fruit != ""]
}
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
uppercase_fruits = [
   "apple",
   "banana",
   "orange",
   "grape",
]
In this example the for expression is iterating over the fruits list and using an if clause to filter out the empty strings (""). This is known as a 'filter'. The result of this will be a brand new list containing only the non-empty strings.

Element Ordering in For Expressions

When the for expressions are used to convert unordered data types like maps, objects and sets into ordered data types like lists and tuples, Terraform needs to make a decision on the order of elements.

Ordering Rules:

variable "fruits" {
    default = {
        d = 4
        a = 1
        c = 3
        d = 2
    } 
}
output "uppercase_fruits" {
    value = {for i,v in var.map : i => tostring(v)}
}
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
tranformed-var = {
    "a" = "1",
    "b" = "2",
    "c" = "3",
    "d" = "4"
}
In the above example, the keys of the output map are sorted alphabetically: "a", "b", "c", "d". The values retain their original order.
variable "fruits" {
    type = set(string)
    default = ["banar", "raja", "ajay"]
}
output "sorted-set" {
    value = [for i in var.set : i]
}
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
sorted-set = [{
    "ajay",
    "banar",
    "raja",
}]
Here, the elements of the output list are soreted in alphabetical order: "ajay", "banar", "raja".
NOTE: Terraform for expression does not preserve and sort the order of elements for Sets of numbers or booleans, Lists, Tuples.

Allowing Duplicate Keys in Map or Object

While creating an object in Terraform delimited by {}, all keys should be unique. If there is any duplication in keys, Terraform throws an error. Sometimes you will have a situation where many values have to share the same key. For example, think of the case where there is a list of users and their respective roles. If you try to create a map from this list using the role as the key, you get an error because of the duplicate keys.
variable "duplicate_keys" {
    default = {
        ajay = {
            role = "admin"
        },
        banar = {
            role = "maintainer"
        },
        raja = {
            role = "read-only"
        },
        gavin = {
            role = "read-only"
        }
    }
}
output "keys" {
    value = {for username, value in var.duplicate_keys : value.role => username}
}
Error: Duplicate object key
Two different items produced the key "read-only" in this 'for' expression. If duplicates are expected, use the ellipsis (...) │ after the value expression to enable grouping by key.
To handle this situation, Terraform provides a feature called Grouping Mode. Grouping Mode allows you to create a map where multiple values are associated with a single key. This is particularly useful when working with data that has duplicate keys. To activate Grouping Mode, you simply need to add ... after the value expression in your for loop. This tells Terraform to create a map of lists, where each key can have multiple values.
variable "duplicate_keys" {
    default = {
        ajay = {
            role = "admin"
        },
        banar = {
            role = "maintainer"
        },
        raja = {
            role = "read-only"
        },
        gavin = {
            role = "read-only"
        }
    }
}
output "keys" {
    value = {for username, value in var.duplicate_keys : value.role => username...}
}
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
keys = {
    "admin" = [
        "ajay"
    ],
    "maintainer" = [
        "banar"
    ],
    "read-only" = [
        "raja",
        "gavin"
    ]
}

Related Pages

Feedback

Was this page helpful?