github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/website/docs/language/meta-arguments/for_each.html.md (about) 1 --- 2 layout: "language" 3 page_title: "The for_each Meta-Argument - Configuration Language" 4 description: "The for_each meta-argument allows you to manage similar infrastructure resources without writing a separate block for each one." 5 --- 6 7 # The `for_each` Meta-Argument 8 9 By default, a [resource block](/docs/language/resources/syntax.html) configures one real 10 infrastructure object (and similarly, a 11 [module block](/docs/language/modules/syntax.html) includes a 12 child module's contents into the configuration one time). 13 However, sometimes you want to manage several similar objects (like a fixed 14 pool of compute instances) without writing a separate block for each one. 15 Terraform has two ways to do this: 16 [`count`](/docs/language/meta-arguments/count.html) and `for_each`. 17 18 > **Hands-on:** Try the [Manage Similar Resources With For Each](https://learn.hashicorp.com/tutorials/terraform/for-each?in=terraform/configuration-language) tutorial on HashiCorp Learn. 19 20 If a resource or module block includes a `for_each` argument whose value is a map or 21 a set of strings, Terraform will create one instance for each member of 22 that map or set. 23 24 -> **Version note:** `for_each` was added in Terraform 0.12.6. Module support 25 for `for_each` was added in Terraform 0.13; previous versions can only use 26 it with resources. 27 28 -> **Note:** A given resource or module block cannot use both `count` and `for_each`. 29 30 ## Basic Syntax 31 32 `for_each` is a meta-argument defined by the Terraform language. It can be used 33 with modules and with every resource type. 34 35 The `for_each` meta-argument accepts a map or a set of strings, and creates an 36 instance for each item in that map or set. Each instance has a distinct 37 infrastructure object associated with it, and each is separately created, 38 updated, or destroyed when the configuration is applied. 39 40 Map: 41 42 ```hcl 43 resource "azurerm_resource_group" "rg" { 44 for_each = { 45 a_group = "eastus" 46 another_group = "westus2" 47 } 48 name = each.key 49 location = each.value 50 } 51 ``` 52 53 Set of strings: 54 55 ```hcl 56 resource "aws_iam_user" "the-accounts" { 57 for_each = toset( ["Todd", "James", "Alice", "Dottie"] ) 58 name = each.key 59 } 60 ``` 61 62 Child module: 63 64 ```hcl 65 # my_buckets.tf 66 module "bucket" { 67 for_each = toset(["assets", "media"]) 68 source = "./publish_bucket" 69 name = "${each.key}_bucket" 70 } 71 ``` 72 73 ```hcl 74 # publish_bucket/bucket-and-cloudfront.tf 75 variable "name" {} # this is the input parameter of the module 76 77 resource "aws_s3_bucket" "example" { 78 # Because var.name includes each.key in the calling 79 # module block, its value will be different for 80 # each instance of this module. 81 bucket = var.name 82 83 # ... 84 } 85 86 resource "aws_iam_user" "deploy_user" { 87 # ... 88 } 89 ``` 90 91 ## The `each` Object 92 93 In blocks where `for_each` is set, an additional `each` object is 94 available in expressions, so you can modify the configuration of each instance. 95 This object has two attributes: 96 97 - `each.key` — The map key (or set member) corresponding to this instance. 98 - `each.value` — The map value corresponding to this instance. (If a set was 99 provided, this is the same as `each.key`.) 100 101 ## Limitations on values used in `for_each` 102 103 The keys of the map (or all the values in the case of a set of strings) must 104 be _known values_, or you will get an error message that `for_each` has dependencies 105 that cannot be determined before apply, and a `-target` may be needed. 106 107 `for_each` keys cannot be the result (or rely on the result of) of impure functions, 108 including `uuid`, `bcrypt`, or `timestamp`, as their evaluation is deferred during the 109 main evaluation step. 110 111 Sensitive values, such as [sensitive input variables](https://www.terraform.io/docs/language/values/variables.html#suppressing-values-in-cli-output), 112 [sensitive outputs](https://www.terraform.io/docs/language/values/outputs.html#sensitive-suppressing-values-in-cli-output), 113 or [sensitive resource attributes](https://www.terraform.io/docs/language/expressions/references.html#sensitive-resource-attributes), 114 cannot be used as arguments to `for_each`. The value used in `for_each` is used 115 to identify the resource instance and will always be disclosed in UI output, 116 which is why sensitive values are not allowed. 117 Attempts to use sensitive values as `for_each` arguments will result in an error. 118 119 If you transform a value containing sensitive data into an argument to be used in `for_each`, be aware that 120 [most functions in Terraform will return a sensitive result if given an argument with any sensitive content](https://www.terraform.io/docs/language/expressions/function-calls.html#using-sensitive-data-as-function-arguments). 121 In many cases, you can achieve similar results to a function used for this purpose by 122 using a `for` expression. For example, if you would like to call `keys(local.map)`, where 123 `local.map` is an object with sensitive values (but non-sensitive keys), you can create a 124 value to pass to `for_each` with `toset([for k,v in local.map : k])`. 125 126 ## Using Expressions in `for_each` 127 128 The `for_each` meta-argument accepts map or set [expressions](/docs/language/expressions/index.html). 129 However, unlike most arguments, the `for_each` value must be known 130 _before_ Terraform performs any remote resource actions. This means `for_each` 131 can't refer to any resource attributes that aren't known until after a 132 configuration is applied (such as a unique ID generated by the remote API when 133 an object is created). 134 135 The `for_each` value must be a map or set with one element per desired 136 resource instance. When providing a set, you must use an expression that 137 explicitly returns a set value, like the [`toset`](/docs/language/functions/toset.html) 138 function; to prevent unwanted surprises during conversion, the `for_each` 139 argument does not implicitly convert lists or tuples to sets. 140 If you need to declare resource instances based on a nested 141 data structure or combinations of elements from multiple data structures you 142 can use Terraform expressions and functions to derive a suitable value. 143 For example: 144 145 * Transform a multi-level nested structure into a flat list by 146 [using nested `for` expressions with the `flatten` function](/docs/language/functions/flatten.html#flattening-nested-structures-for-for_each). 147 * Produce an exhaustive list of combinations of elements from two or more 148 collections by 149 [using the `setproduct` function inside a `for` expression](/docs/language/functions/setproduct.html#finding-combinations-for-for_each). 150 151 ### Chaining `for_each` Between Resources 152 153 Because a resource using `for_each` appears as a map of objects when used in 154 expressions elsewhere, you can directly use one resource as the `for_each` 155 of another in situations where there is a one-to-one relationship between 156 two sets of objects. 157 158 For example, in AWS an `aws_vpc` object is commonly associated with a number 159 of other objects that provide additional services to that VPC, such as an 160 "internet gateway". If you are declaring multiple VPC instances using `for_each` 161 then you can chain that `for_each` into another resource to declare an 162 internet gateway for each VPC: 163 164 ```hcl 165 variable "vpcs" { 166 type = map(object({ 167 cidr_block = string 168 })) 169 } 170 171 resource "aws_vpc" "example" { 172 # One VPC for each element of var.vpcs 173 for_each = var.vpcs 174 175 # each.value here is a value from var.vpcs 176 cidr_block = each.value.cidr_block 177 } 178 179 resource "aws_internet_gateway" "example" { 180 # One Internet Gateway per VPC 181 for_each = aws_vpc.example 182 183 # each.value here is a full aws_vpc object 184 vpc_id = each.value.id 185 } 186 187 output "vpc_ids" { 188 value = { 189 for k, v in aws_vpc.example : k => v.id 190 } 191 192 # The VPCs aren't fully functional until their 193 # internet gateways are running. 194 depends_on = [aws_internet_gateway.example] 195 } 196 ``` 197 198 This chaining pattern explicitly and concisely declares the relationship 199 between the internet gateway instances and the VPC instances, which tells 200 Terraform to expect the instance keys for both to always change together, 201 and typically also makes the configuration easier to understand for human 202 maintainers. 203 204 ## Referring to Instances 205 206 When `for_each` is set, Terraform distinguishes between the block itself 207 and the multiple _resource or module instances_ associated with it. Instances are 208 identified by a map key (or set member) from the value provided to `for_each`. 209 210 - `<TYPE>.<NAME>` or `module.<NAME>` (for example, `azurerm_resource_group.rg`) refers to the block. 211 - `<TYPE>.<NAME>[<KEY>]` or `module.<NAME>[<KEY>]` (for example, `azurerm_resource_group.rg["a_group"]`, 212 `azurerm_resource_group.rg["another_group"]`, etc.) refers to individual instances. 213 214 This is different from resources and modules without `count` or `for_each`, which can be 215 referenced without an index or key. 216 217 Similarly, resources from child modules with multiple instances are prefixed 218 with `module.<NAME>[<KEY>]` when displayed in plan output and elsewhere in the UI. 219 For a module without `count` or `for_each`, the address will not contain 220 the module index as the module's name suffices to reference the module. 221 222 -> **Note:** Within nested `provisioner` or `connection` blocks, the special 223 `self` object refers to the current _resource instance,_ not the resource block 224 as a whole. 225 226 ## Using Sets 227 228 The Terraform language doesn't have a literal syntax for 229 [set values](/docs/language/expressions/type-constraints.html#collection-types), but you can use the `toset` 230 function to explicitly convert a list of strings to a set: 231 232 ```hcl 233 locals { 234 subnet_ids = toset([ 235 "subnet-abcdef", 236 "subnet-012345", 237 ]) 238 } 239 240 resource "aws_instance" "server" { 241 for_each = local.subnet_ids 242 243 ami = "ami-a1b2c3d4" 244 instance_type = "t2.micro" 245 subnet_id = each.key # note: each.key and each.value are the same for a set 246 247 tags = { 248 Name = "Server ${each.key}" 249 } 250 } 251 ``` 252 253 Conversion from list to set discards the ordering of the items in the list and 254 removes any duplicate elements. `toset(["b", "a", "b"])` will produce a set 255 containing only `"a"` and `"b"` in no particular order; the second `"b"` is 256 discarded. 257 258 If you are writing a module with an [input variable](/docs/language/values/variables.html) that 259 will be used as a set of strings for `for_each`, you can set its type to 260 `set(string)` to avoid the need for an explicit type conversion: 261 262 ```hcl 263 variable "subnet_ids" { 264 type = set(string) 265 } 266 267 resource "aws_instance" "server" { 268 for_each = var.subnet_ids 269 270 # (and the other arguments as above) 271 } 272 ```