1"use strict";(globalThis.webpackChunkwebsite=globalThis.webpackChunkwebsite||[]).push([[5806],{73447(e,n,s){s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>h,frontMatter:()=>o,metadata:()=>a,toc:()=>l});let a=JSON.parse('{"id":"language/meta-arguments/for_each","title":"The for_each Meta-Argument","description":"The for_each meta-argument allows you to manage similar infrastructure resources without writing a separate block for each one.","source":"@site/versioned_docs/version-v1.13/language/meta-arguments/for_each.mdx","sourceDirName":"language/meta-arguments","slug":"/language/meta-arguments/for_each","permalink":"/docs/v1.13/language/meta-arguments/for_each","draft":false,"unlisted":false,"editUrl":"https://github.com/opentofu/opentofu/edit/v1.13/website/docs/language/meta-arguments/for_each.mdx","tags":[],"version":"v1.13","frontMatter":{"description":"The for_each meta-argument allows you to manage similar infrastructure resources without writing a separate block for each one."},"sidebar":"docs","previous":{"title":"The enabled Meta-Argument","permalink":"/docs/v1.13/language/meta-arguments/enabled"},"next":{"title":"lifecycle Blocks","permalink":"/docs/v1.13/language/meta-arguments/lifecycle"}}');var r=s(74848),t=s(28453);let o={description:"The for_each meta-argument allows you to manage similar infrastru
1cture resources without writing a separate block for each one."},i="The for_each Meta-Argument",c={},l=[{value:"Basic Syntax",id:"basic-syntax",level:2},{value:"The <code>each</code> Object",id:"the-each-object",level:2},{value:"Limitations on values used in <code>for_each</code>",id:"limitations-on-values-used-in-for_each",level:2},{value:"Using Expressions in <code>for_each</code>",id:"using-expressions-in-for_each",level:2},{value:"Chaining <code>for_each</code> Between Resources",id:"chaining-for_each-between-resources",level:3},{value:"Referring to Instances",id:"referring-to-instances",level:2},{value:"Using Sets",id:"using-sets",level:2}];function d(e){let n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,t.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsxs)(n.h1,{id:"the-for_each-meta-argument",children:["The ",(0,r.jsx)(n.code,{children:"for_each"})," Meta-Argument"]})}),"\n",(0,r.jsxs)(n.p,{children:["By default, a ",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/resources/syntax",children:"resource block"})," configures one real\ninfrastructure object (and similarly, a\n",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/modules/syntax",children:"module block"})," includes a\nchild module's contents into the configuration one time).\nHowever, sometimes you want to manage several similar objects (like a fixed\npool of compute instances) without writing a separate block for each one.\nOpenTofu has two ways to do this:\n",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/meta-arguments/count",children:(0,r.jsx)(n.code,{children:"count"})})," and ",(0,r.jsx)(n.code,{children:"for_each"}),"."]}),"\n",(0,r.jsxs)(n.p,{children:["If a resource or module block includes a ",(0,r.jsx)(n.code,{children:"for_each"})," argument whose value is a map or\na set of strings, OpenTofu creates one instance for each member of\nthat map or set."]}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["A given resource or module block cannot use ",(0,r.jsx)(n.code,{children:"for_each"})," together with ",(0,r.jsx)(n.code,{children:"count"})," or ",(0,r.jsx)(n.code,{children:"enabled"}),"."]})}),"\n",(0,r.jsx)(n.h2,{id:"basic-syntax",children:"Basic Syntax"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"for_each"})," is a meta-argument defined by the OpenTofu language. It can be used\nwith modules and with every resource type."]}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"for_each"})," meta-argument accepts a map or a set of strings, and creates an\ninstance for each item in that map or set. Each instance has a distinct\ninfrastructure object associated with it, and each is separately created,\nupdated, or destroyed when the configuration is applied."]}),"\n",(0,r.jsx)(n.p,{children:"Map:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'resource "azurerm_resource_group" "rg" {\n for_each = {\n a_group = "eastus"\n another_group = "westus2"\n }\n name = each.key\n location = each.value\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:"Set of strings:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'resource "aws_iam_user" "the-accounts" {\n for_each = toset( ["Todd", "James", "Alice", "Dottie"] )\n name = each.key\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:"Child module:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'# my_buckets.tf\nmodule "bucket" {\n for_each = toset(["assets", "media"])\n source = "./publish_bucket"\n name = "${each.key}_bucket"\n}\n'})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'# publish_bucket/bucket-and-cloudfront.tf\nvariable "name" {} # this is the input parameter of the module\n\nresource "aws_s3_bucket" "example" {\n # Because var.name includes each.key in the calling\n # module block, its value will be different for\n # each instance of this module.\n bucket = var.name\n\n # ...\n}\n\nresource "aws_iam_user" "deploy_user" {\n # ...\n}\n'})}),"\n",(0,r.jsxs)(n.h2,{id:"the-each-object",children:["The ",(0,r.jsx)(n.code,{children:"each"})," Object"]}),"\n",(0,r.jsxs)(n.p,{children:["In blocks where ",(0,r.jsx)(n.code,{children:"for_each"})," is set, an additional ",(0,r.jsx)(n.code,{children:"each"})," object is\navailable in expressions, so you can modify the configuration of each instance.\nThis object has two attributes:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"each.key"})," \u2014\xa0The map key (or set member) corresponding to this instance."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"each.value"})," \u2014 The map value corresponding to this instance. (If a set was\nprovided, this is the same as ",(0,r.jsx)(n.code,{children:"each.key"}),".)"]}),"\n"]}),"\n",(0,r.jsxs)(n.h2,{id:"limitations-on-values-used-in-for_each",children:["Limitations on values used in ",(0,r.jsx)(n.code,{children:"for_each"})]}),"\n",(0,r.jsxs)(n.p,{children:["The keys of the map (or all the values in the case of a set of strings) must\nbe ",(0,r.jsx)(n.em,{children:"known values"}),", or you will get an error message that ",(0,r.jsx)(n.code,{children:"for_each"})," has dependencies\nthat cannot be determined before apply, and a ",(0,r.jsx)(n.code,{children:"-target"}),"/",(0,r.jsx)(n.code,{children:"-exclude"})," may be needed."]}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"for_each"})," keys cannot be the result (or rely on the result of) of impure functions,\nincluding ",(0,r.jsx)(n.code,{children:"uuid"}),", ",(0,r.jsx)(n.code,{children:"bcrypt"}),", or ",(0,r.jsx)(n.code,{children:"timestamp"}),", as their evaluation is deferred during the\nmain evaluation step."]}),"\n",(0,r.jsxs)(n.p,{children:["Sensitive values, such as ",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/values/variables#suppressing-values-in-cli-output",children:"sensitive input variables"}),",\n",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/values/outputs#sensitive-suppressing-values-in-cli-output",children:"sensitive outputs"}),",\nor ",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/expressions/references#sensitive-resource-attributes",children:"sensitive resource attributes"}),",\ncannot be used as arguments to ",(0,r.jsx)(n.code,{children:"for_each"}),". The value used in ",(0,r.jsx)(n.code,{children:"for_each"})," is used\nto identify the resource instance and will always be disclosed in UI output,\nwhich is why sensitive values are not allowed.\nAttempts to use sensitive values as ",(0,r.jsx)(n.code,{children:"for_each"})," arguments will result in an error."]}),"\n",(0,r.jsxs)(n.p,{children:["If you transform a value containing sensitive data into an argument to be used in ",(0,r.jsx)(n.code,{children:"for_each"}),", be aware that\n",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/expressions/function-calls#using-sensitive-data-as-function-arguments",children:"most functions in OpenTofu will return a sensitive result if given an argument with any sensitive content"}),".\nIn many cases, you can achieve similar results to a function used for this purpose by\nusing a ",(0,r.jsx)(n.code,{children:"for"})," expression. For example, if you would like to call ",(0,r.jsx)(n.code,{children:"keys(local.map
1)"}),", where\n",(0,r.jsx)(n.code,{children:"local.map"})," is an object with sensitive values (but non-sensitive keys), you can create a\nvalue to pass to ",(0,r.jsx)(n.code,{children:"for_each"})," with ",(0,r.jsx)(n.code,{children:"toset([for k,v in local.map : k])"}),"."]}),"\n",(0,r.jsxs)(n.h2,{id:"using-expressions-in-for_each",children:["Using Expressions in ",(0,r.jsx)(n.code,{children:"for_each"})]}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"for_each"})," meta-argument accepts map or set ",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/expressions/",children:"expressions"}),".\nHowever, unlike most arguments, the ",(0,r.jsx)(n.code,{children:"for_each"})," value must be known\n",(0,r.jsx)(n.em,{children:"before"})," OpenTofu performs any remote resource actions. This means ",(0,r.jsx)(n.code,{children:"for_each"}),"\ncan't refer to any resource attributes that aren't known until after a\nconfiguration is applied (such as a unique ID generated by the remote API when\nan object is created)."]}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"for_each"})," value must be a map or set with one element per desired resource\ninstance. To use a sequence as the ",(0,r.jsx)(n.code,{children:"for_each"})," value, you must use an expression\nthat explicitly returns a set value, like the ",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/functions/toset",children:"toset"}),"\nfunction. To prevent unwanted surprises during conversion, the ",(0,r.jsx)(n.code,{children:"for_each"})," argument\ndoes not implicitly convert lists or tuples to sets.\nIf you need to declare resource instances based on a nested\ndata structure or combinations of elements from multiple data structures you\ncan use OpenTofu expressions and functions to derive a suitable value.\nFor example:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["Transform a multi-level nested structure into a flat list by\n",(0,r.jsxs)(n.a,{href:"/docs/v1.13/language/functions/flatten#flattening-nested-structures-for-for_each",children:["using nested ",(0,r.jsx)(n.code,{children:"for"})," expressions with the ",(0,r.jsx)(n.code,{children:"flatten"})," function"]}),"."]}),"\n",(0,r.jsxs)(n.li,{children:["Produce an exhaustive list of combinations of elements from two or more\ncollections by\n",(0,r.jsxs)(n.a,{href:"/docs/v1.13/language/functions/setproduct#finding-combinations-for-for_each",children:["using the ",(0,r.jsx)(n.code,{children:"setproduct"})," function inside a ",(0,r.jsx)(n.code,{children:"for"})," expression"]}),"."]}),"\n"]}),"\n",(0,r.jsxs)(n.h3,{id:"chaining-for_each-between-resources",children:["Chaining ",(0,r.jsx)(n.code,{children:"for_each"})," Between Resources"]}),"\n",(0,r.jsxs)(n.p,{children:["Because a resource using ",(0,r.jsx)(n.code,{children:"for_each"})," appears as a map of objects when used in\nexpressions elsewhere, you can directly use one resource as the ",(0,r.jsx)(n.code,{children:"for_each"}),"\nof another in situations where there is a one-to-one relationship between\ntwo sets of objects."]}),"\n",(0,r.jsxs)(n.p,{children:["For example, in AWS an ",(0,r.jsx)(n.code,{children:"aws_vpc"}),' object is commonly associated with a number\nof other objects that provide additional services to that VPC, such as an\n"internet gateway". If you are declaring multiple VPC instances using ',(0,r.jsx)(n.code,{children:"for_each"}),"\nthen you can chain that ",(0,r.jsx)(n.code,{children:"for_each"})," into another resource to declare an\ninternet gateway for each VPC:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'variable "vpcs" {\n type = map(object({\n cidr_block = string\n }))\n}\n\nresource "aws_vpc" "example" {\n # One VPC for each element of var.vpcs\n for_each = var.vpcs\n\n # each.value here is a value from var.vpcs\n cidr_block = each.value.cidr_block\n}\n\nresource "aws_internet_gateway" "example" {\n # One Internet Gateway per VPC\n for_each = aws_vpc.example\n\n # each.value here is a full aws_vpc object\n vpc_id = each.value.id\n}\n\noutput "vpc_ids" {\n value = {\n for k, v in aws_vpc.example : k => v.id\n }\n\n # The VPCs aren\'t fully functional until their\n # internet gateways are running.\n depends_on = [aws_internet_gateway.example]\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:"This chaining pattern explicitly and concisely declares the relationship\nbetween the internet gateway instances and the VPC instances, which tells\nOpenTofu to expect the instance keys for both to always change together,\nand typically also makes the configuration easier to understand for human\nmaintainers."}),"\n",(0,r.jsx)(n.h2,{id:"referring-to-instances",children:"Referring to Instances"}),"\n",(0,r.jsxs)(n.p,{children:["When ",(0,r.jsx)(n.code,{children:"for_each"})," is set, OpenTofu distinguishes between the block itself\nand the multiple ",(0,r.jsx)(n.em,{children:"resource or module instances"})," associated with it. Instances are\nidentified by a map key (or set member) from the value provided to ",(0,r.jsx)(n.code,{children:"for_each"}),"."]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"<TYPE>.<NAME>"})," or ",(0,r.jsx)(n.code,{children:"module.<NAME>"})," (for example, ",(0,r.jsx)(n.code,{children:"azurerm_resource_group.rg"}),") refers to the block."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"<TYPE>.<NAME>[<KEY>]"})," or ",(0,r.jsx)(n.code,{children:"module.<NAME>[<KEY>]"})," (for example, ",(0,r.jsx)(n.code,{children:'azurerm_resource_group.rg["a_group"]'}),",\n",(0,r.jsx)(n.code,{children:'azurerm_resource_group.rg["another_group"]'}),", etc.) refers to individual instances."]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["This is different from resources and modules without ",(0,r.jsx)(n.code,{children:"count"})," or ",(0,r.jsx)(n.code,{children:"for_each"}),", which can be\nreferenced without an index or key."]}),"\n",(0,r.jsxs)(n.p,{children:["Similarly, resources from child modules with multiple instances are prefixed\nwith ",(0,r.jsx)(n.code,{children:"module.<NAME>[<KEY>]"})," when displayed in plan output and elsewhere in the UI.\nFor a module without ",(0,r.jsx)(n.code,{children:"count"})," or ",(0,r.jsx)(n.code,{children:"for_each"}),", the address will not contain\nthe module index as the module's name suffices to reference the module."]}),"\n",(0,r.jsx)(n.admonition,{type:"note",children:(0,r.jsxs)(n.p,{children:["Within nested ",(0,r.jsx)(n.code,{children:"provisioner"})," or ",(0,r.jsx)(n.code,{children:"connection"})," blocks, the special\n",(0,r.jsx)(n.code,{children:"self"})," object refers to the current ",(0,r.jsx)(n.em,{children:"resource instance,"})," not the resource block\nas a whole."]})}),"\n",(0,r.jsx)(n.h2,{id:"using-sets",children:"Using Sets"}),"\n",(0,r.jsxs)(n.p,{children:["The OpenTofu language doesn't have a literal syntax for\n",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/expressions/type-constraints#collection-types",children:"set values"}),", but you can use the ",(0,r.jsx)(n.code,{children:"toset"}),"\nfunction to explicitly convert a list of strings to a set:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'locals {\n subnet_ids = toset([\n "subnet-abcdef",\n "subnet-012345",\n ])\n}\n\nresource "aws_instance" "server" {\n for_each = local.subnet_ids\n\n ami = "ami-a1b2c3d4"\n instance_type = "t2.micro"\n subnet_id = each.key # note: each.key and each.value are the same for a set\n\n tags = {\n Name = "Server ${each.key}"\n }\n}\n'})}),"\n",(0,r.jsxs)(n.p,{children:["Conversion from list to set discards the ordering of the items in the list and\nremoves any duplicate elements. ",(0,r.jsx)(n.code,{children:'toset(["b", "a", "b"])'})," will produce a set\ncontaining only ",(0,r.jsx)(n.code,{children:'"a"'})," and ",(0,r.jsx)(n.code,{children:'"b"'})," in no particular order; the second ",(0,r.jsx)(n.code,{children:'"b"'})," is\ndiscarded."]}),"\n",(0,r.jsxs)(n.p,{children:["If you are writing a module with an ",(0,r.jsx)(n.a,{href:"/docs/v1.13/language/values/variables",children:"input variable"})," that\nwill be used as a set of strings for ",(0,r.jsx)(n.code,{children:"for_each"}),", you can set its type to\n",(0,r.jsx)(n.code,{children:"set(string)"})," to avoid the need for an explicit type conversion:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-hcl",children:'variable "subnet_ids" {\n type = set(string)\n}\n\nresource "aws_instance" "server" {\n for_each = var.subnet_ids\n\n # (and the other arguments as above)\n}\n'})})]})}function h(e={}){let{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}},28453(e,n,s){s.d(n,{R:()=>o,x:()=>i});var a=s(96540);let r={},t=a.createContext(r);function o(e){let n=a.useContext(t);return a.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),a.createElement(t.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.