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  ```