github.com/hugorut/terraform@v1.1.3/website/docs/language/expressions/for.mdx (about) 1 --- 2 page_title: For Expressions - Configuration Language 3 description: >- 4 For expressions transform complex input values into complex output values. 5 Learn how to filter inputs and how to group results. 6 --- 7 8 # `for` Expressions 9 10 A _`for` expression_ creates a complex type value by transforming 11 another complex type value. Each element in the input value 12 can correspond to either one or zero values in the result, and an arbitrary 13 expression can be used to transform each input element into an output element. 14 15 For example, if `var.list` were a list of strings, then the following expression 16 would produce a tuple of strings with all-uppercase letters: 17 18 ```hcl 19 [for s in var.list : upper(s)] 20 ``` 21 22 This `for` expression iterates over each element of `var.list`, and then 23 evaluates the expression `upper(s)` with `s` set to each respective element. 24 It then builds a new tuple value with all of the results of executing that 25 expression in the same order. 26 27 ## Input Types 28 29 A `for` expression's input (given after the `in` keyword) can be a list, 30 a set, a tuple, a map, or an object. 31 32 The above example showed a `for` expression with only a single temporary 33 symbol `s`, but a `for` expression can optionally declare a pair of temporary 34 symbols in order to use the key or index of each item too: 35 36 ```hcl 37 [for k, v in var.map : length(k) + length(v)] 38 ``` 39 40 For a map or object type, like above, the `k` symbol refers to the key or 41 attribute name of the current element. You can also use the two-symbol form 42 with lists and tuples, in which case the additional symbol is the index 43 of each element starting from zero, which conventionally has the symbol name 44 `i` or `idx` unless it's helpful to choose a more specific name: 45 46 ```hcl 47 [for i, v in var.list : "${i} is ${v}"] 48 ``` 49 50 The index or key symbol is always optional. If you specify only a single 51 symbol after the `for` keyword then that symbol will always represent the 52 _value_ of each element of the input collection. 53 54 ## Result Types 55 56 The type of brackets around the `for` expression decide what type of result 57 it produces. 58 59 The above example uses `[` and `]`, which produces a tuple. If you use `{` and 60 `}` instead, the result is an object and you must provide two result 61 expressions that are separated by the `=>` symbol: 62 63 ```hcl 64 {for s in var.list : s => upper(s)} 65 ``` 66 67 This expression produces an object whose attributes are the original elements 68 from `var.list` and their corresponding values are the uppercase versions. 69 For example, the resulting value might be as follows: 70 71 ```hcl 72 { 73 foo = "FOO" 74 bar = "BAR" 75 baz = "BAZ" 76 } 77 ``` 78 79 A `for` expression alone can only produce either an object value or a tuple 80 value, but Terraform's automatic type conversion rules mean that you can 81 typically use the results in locations where lists, maps, and sets are expected. 82 83 ## Filtering Elements 84 85 A `for` expression can also include an optional `if` clause to filter elements 86 from the source collection, producing a value with fewer elements than 87 the source value: 88 89 ``` 90 [for s in var.list : upper(s) if s != ""] 91 ``` 92 93 One common reason for filtering collections in `for` expressions is to split 94 a single source collection into two separate collections based on some 95 criteria. For example, if the input `var.users` is a map of objects where the 96 objects each have an attribute `is_admin` then you may wish to produce separate 97 maps with admin vs non-admin objects: 98 99 ```hcl 100 variable "users" { 101 type = map(object({ 102 is_admin = bool 103 })) 104 } 105 106 locals { 107 admin_users = { 108 for name, user in var.users : name => user 109 if user.is_admin 110 } 111 regular_users = { 112 for name, user in var.users : name => user 113 if !user.is_admin 114 } 115 } 116 ``` 117 118 ## Element Ordering 119 120 Because `for` expressions can convert from unordered types (maps, objects, sets) 121 to ordered types (lists, tuples), Terraform must choose an implied ordering 122 for the elements of an unordered collection. 123 124 For maps and objects, Terraform sorts the elements by key or attribute name, 125 using lexical sorting. 126 127 For sets of strings, Terraform sorts the elements by their value, using 128 lexical sorting. 129 130 For sets of other types, Terraform uses an arbitrary ordering that may change 131 in future versions of Terraform. For that reason, we recommend converting the 132 result of such an expression to itself be a set so that it's clear elsewhere 133 in the configuration that the result is unordered. You can use 134 [the `toset` function](/language/functions/toset) 135 to concisely convert a `for` expression result to be of a set type. 136 137 ```hcl 138 toset([for e in var.set : e.example]) 139 ``` 140 141 ## Grouping Results 142 143 If the result type is an object (using `{` and `}` delimiters) then normally 144 the given key expression must be unique across all elements in the result, 145 or Terraform will return an error. 146 147 Sometimes the resulting keys are _not_ unique, and so to support that situation 148 Terraform supports a special _grouping mode_ which changes the result to support 149 multiple elements per key. 150 151 To activate grouping mode, add the symbol `...` after the value expression. 152 For example: 153 154 ```hcl 155 variable "users" { 156 type = map(object({ 157 role = string 158 })) 159 } 160 161 locals { 162 users_by_role = { 163 for name, user in var.users : user.role => name... 164 } 165 } 166 ``` 167 168 The above represents a situation where a module expects a map describing 169 various users who each have a single "role", where the map keys are usernames. 170 The usernames are guaranteed unique because they are map keys in the input, 171 but many users may all share a single role name. 172 173 The `local.users_by_role` expression inverts the input map so that the keys 174 are the role names and the values are usernames, but the expression is in 175 grouping mode (due to the `...` after `name`) and so the result will be a 176 map of lists of strings, such as the following: 177 178 ```hcl 179 { 180 "admin": [ 181 "ps", 182 ], 183 "maintainer": [ 184 "am", 185 "jb", 186 "kl", 187 "ma", 188 ], 189 "viewer": [ 190 "st", 191 "zq", 192 ], 193 } 194 ``` 195 196 Due to [the element ordering rules](#element-ordering), Terraform will sort 197 the users lexically by username as part of evaluating the `for` expression, 198 and so the usernames associated with each role will be lexically sorted 199 after grouping. 200 201 ## Repeated Configuration Blocks 202 203 The `for` expressions mechanism is for constructing collection values from 204 other collection values within expressions, which you can then assign to 205 individual resource arguments that expect complex values. 206 207 Some resource types also define _nested block types_, which typically represent 208 separate objects that belong to the containing resource in some way. You can't 209 dynamically generate nested blocks using `for` expressions, but you _can_ 210 generate nested blocks for a resource dynamically using 211 [`dynamic` blocks](/language/expressions/dynamic-blocks).