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