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).