github.com/hugorut/terraform@v1.1.3/website/docs/language/expressions/dynamic-blocks.mdx (about)

     1  ---
     2  page_title: Dynamic Blocks - Configuration Language
     3  description: >-
     4    Dynamic blocks automatically construct multi-level, nested block structures.
     5    Learn to configure dynamic blocks and understand their behavior.
     6  ---
     7  
     8  # `dynamic` Blocks
     9  
    10  Within top-level block constructs like resources, expressions can usually be
    11  used only when assigning a value to an argument using the `name = expression`
    12  form. This covers many uses, but some resource types include repeatable _nested
    13  blocks_ in their arguments, which typically represent separate objects that
    14  are related to (or embedded within) the containing object:
    15  
    16  ```hcl
    17  resource "aws_elastic_beanstalk_environment" "tfenvtest" {
    18    name = "tf-test-name" # can use expressions here
    19  
    20    setting {
    21      # but the "setting" block is always a literal block
    22    }
    23  }
    24  ```
    25  
    26  You can dynamically construct repeatable nested blocks like `setting` using a
    27  special `dynamic` block type, which is supported inside `resource`, `data`,
    28  `provider`, and `provisioner` blocks:
    29  
    30  ```hcl
    31  resource "aws_elastic_beanstalk_environment" "tfenvtest" {
    32    name                = "tf-test-name"
    33    application         = "${aws_elastic_beanstalk_application.tftest.name}"
    34    solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"
    35  
    36    dynamic "setting" {
    37      for_each = var.settings
    38      content {
    39        namespace = setting.value["namespace"]
    40        name = setting.value["name"]
    41        value = setting.value["value"]
    42      }
    43    }
    44  }
    45  ```
    46  
    47  A `dynamic` block acts much like a [`for` expression](/language/expressions/for), but produces
    48  nested blocks instead of a complex typed value. It iterates over a given
    49  complex value, and generates a nested block for each element of that complex
    50  value.
    51  
    52  - The label of the dynamic block (`"setting"` in the example above) specifies
    53    what kind of nested block to generate.
    54  - The `for_each` argument provides the complex value to iterate over.
    55  - The `iterator` argument (optional) sets the name of a temporary variable
    56    that represents the current element of the complex value. If omitted, the name
    57    of the variable defaults to the label of the `dynamic` block (`"setting"` in
    58    the example above).
    59  - The `labels` argument (optional) is a list of strings that specifies the block
    60    labels, in order, to use for each generated block. You can use the temporary
    61    iterator variable in this value.
    62  - The nested `content` block defines the body of each generated block. You can
    63    use the temporary iterator variable inside this block.
    64  
    65  Since the `for_each` argument accepts any collection or structural value,
    66  you can use a `for` expression or splat expression to transform an existing
    67  collection.
    68  
    69  The iterator object (`setting` in the example above) has two attributes:
    70  
    71  - `key` is the map key or list element index for the current element. If the
    72    `for_each` expression produces a _set_ value then `key` is identical to
    73    `value` and should not be used.
    74  - `value` is the value of the current element.
    75  
    76  A `dynamic` block can only generate arguments that belong to the resource type,
    77  data source, provider or provisioner being configured. It is _not_ possible
    78  to generate meta-argument blocks such as `lifecycle` and `provisioner`
    79  blocks, since Terraform must process these before it is safe to evaluate
    80  expressions.
    81  
    82  The `for_each` value must be a collection with one element per desired
    83  nested block. If you need to declare resource instances based on a nested
    84  data structure or combinations of elements from multiple data structures you
    85  can use Terraform expressions and functions to derive a suitable value.
    86  For some common examples of such situations, see the
    87  [`flatten`](/language/functions/flatten)
    88  and
    89  [`setproduct`](/language/functions/setproduct)
    90  functions.
    91  
    92  ## Multi-level Nested Block Structures
    93  
    94  Some providers define resource types that include multiple levels of blocks
    95  nested inside one another. You can generate these nested structures dynamically
    96  when necessary by nesting `dynamic` blocks in the `content` portion of other
    97  `dynamic` blocks.
    98  
    99  For example, a module might accept a complex data structure like the following:
   100  
   101  ```hcl
   102  variable "load_balancer_origin_groups" {
   103    type = map(object({
   104      origins = set(object({
   105        hostname = string
   106      }))
   107    }))
   108  }
   109  ```
   110  
   111  If you were defining a resource whose type expects a block for each origin
   112  group and then nested blocks for each origin within a group, you could ask
   113  Terraform to generate that dynamically using the following nested `dynamic`
   114  blocks:
   115  
   116  ```hcl
   117    dynamic "origin_group" {
   118      for_each = var.load_balancer_origin_groups
   119      content {
   120        name = origin_group.key
   121  
   122        dynamic "origin" {
   123          for_each = origin_group.value.origins
   124          content {
   125            hostname = origin.value.hostname
   126          }
   127        }
   128      }
   129    }
   130  ```
   131  
   132  When using nested `dynamic` blocks it's particularly important to pay attention
   133  to the iterator symbol for each block. In the above example,
   134  `origin_group.value` refers to the current element of the outer block, while
   135  `origin.value` refers to the current element of the inner block.
   136  
   137  If a particular resource type defines nested blocks that have the same type
   138  name as one of their parents, you can use the `iterator` argument in each of
   139  `dynamic` blocks to choose a different iterator symbol that makes the two
   140  easier to distinguish.
   141  
   142  ## Best Practices for `dynamic` Blocks
   143  
   144  Overuse of `dynamic` blocks can make configuration hard to read and maintain, so
   145  we recommend using them only when you need to hide details in order to build a
   146  clean user interface for a re-usable module. Always write nested blocks out
   147  literally where possible.
   148  
   149  If you find yourself defining most or all of a `resource` block's arguments and
   150  nested blocks using directly-corresponding attributes from an input variable
   151  then that might suggest that your module is not creating a useful abstraction.
   152  It may be better for the calling module to define the resource itself then
   153  pass information about it into your module. For more information on this design
   154  tradeoff, see [When to Write a Module](/language/modules/develop#when-to-write-a-module)
   155  and [Module Composition](/language/modules/develop/composition).