Answers: <p>Terraform offers two resource repetition mechanisms: <a href="https://www.terraform.io/docs/configuration/resources.html#count-multiple-resource-instances-by-count" rel="nofollow noreferrer"><code>count</code></a> and <a href="https://www.terraform.io/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings" rel="nofollow noreferrer"><code>for_each</code></a>. The main difference between these is how Terraform will track the multiple instances they create:</p>
  
  <ul>
  <li>When using <code>count</code>, each of the multiple instances is tracked by a number starting at 0, giving addresses like <code>aws_vpc.vpc[0]</code> and <code>aws_vpc.vpc[1]</code>.</li>
  <li>When using <code>for_each</code>, each of the multiple instances is tracked by a string which could be obtained either from a key in a map or from an element in a set, giving addresses like <code>aws_vpc.vpc["10.0.0.0/16"]</code> and <code>aws_vpc.vpc["10.1.0.0/16"]</code>.</li>
  </ul>
  
  <p>The most common reason to choose <code>for_each</code> rather than <code>count</code> is to ensure that the order of whatever collection of values is driving the repetition is not significant. In your specific case, that would produce the same result regardless of whether <code>var.vpc_cidrs</code> is <code>["10.0.0.0/16", "10.1.0.0/16"]</code> or <code>["10.1.0.0/16", "10.0.0.0/16"]</code>, because the instances would be tracked by the CIDR block string and the index in the list is totally ignored.</p>
  
  <p>With that all said, the reason why the index isn't directly available when using <code>for_each</code> is that this would defeat the main purpose of using <code>for_each</code>: it would make the order significant again. In your specific situation, if you used the index in the tag Name then changing the order of the list would cause Terraform to plan to swap the tagging on those two VPCs:</p>
  
  <pre><code> # aws_vpc.vpc["10.0.0.0/16"] will be updated in-place
   ~ resource "aws_vpc" "vpc" {
       ~ tags = {
           ~ Name = "Company01" -&gt; "Company02"
         }
       # ...
     }
  
   # aws_vpc.vpc["10.0.0.0/16"] will be updated in-place
   ~ resource "aws_vpc" "vpc" {
       ~ tags = {
           ~ Name = "Company02" -&gt; "Company01"
         }
       # ...
     }
  </code></pre>
  
  <p>Perhaps that is fine for your case, if those numbers are just there to create some uniqueness and it doesn't matter if they get reassigned over time as CIDR blocks are added, removed and reordered in the input variable. If that's true, then we can derive a value that contains the original index and use that as part of <code>for_each</code> like this:</p>
  
  <pre><code>resource "aws_vpc" "vpc" {
    for_each = { for i, b in var.vpc_cidrs : b =&gt; { index = i } }
  
    cidr_block           = each.key
    tags = {
      Name = format("Company%02d", each.value.index + 1)
    }
  }
  </code></pre>
  
  <p>If you consider the position in the list to be truly significant though -- for example, if you'd want swapping two elements in the list to change the <code>cidr_block</code> values on the two existing objects rather than to re-tag them, it would be more appropriate to use <code>count</code> so that Terraform tracks them by the indices itself:</p>
  
  <pre><code>resource "aws_vpc" "vpc" {
    count = length(var.vpc_cidrs)
  
    cidr_block           = var.vpc_cidrs[count.index]
    tags = {
      Name = format("Company%02d", count.index + 1)
    }
  }
  </code></pre>
  
Answers: CC BY-SA 4.0
Answers: 2021-08-20T05:11:34.307Z
Answers: One of the best explanations there is. Figures it comes from you... :)
Answers: ZenMaster
Answers: CC BY-SA 4.0
Answers: 2020-04-22T22:25:37.020Z
Answers: 2020-04-22T22:25:37.020Z
Answers: Martin Atkins
Answers: <p>You could use without index:</p>
  <pre><code>resource &quot;aws_vpc&quot; &quot;vpc&quot; {
    for_each = { for i, b in var.vpc_cidrs : i =&gt; b }
  
    cidr_block           = each.value
    tags = {
      Name = format(&quot;Company%02d&quot;, each.key + 1)
    }
  }
  </code></pre>
  <p>each.key = index number</p>
  
Answers: CC BY-SA 4.0
Answers: 2022-04-02T15:04:21.520Z
Answers: 2022-04-02T15:04:21.520Z
Answers: Lucas
Answers: <p>Found an easy solution using the <a href="https://www.terraform.io/docs/configuration/functions/index.html" rel="nofollow noreferrer">index</a> function:</p>
  
  <pre><code>tags = { Name = "Company0${index(var.vpc_cidrs, each.value) + 1}" }
  </code></pre>
  
Answers: CC BY-SA 4.0
Answers: 2020-04-21T14:16:20.917Z
Answers: 2020-04-21T14:16:20.917Z
Answers: Moshe
Body: <p>Terraform newbie here. I'd like to iterate a list using <code>for_each</code>, but it seems like the key and value are the same:</p>
  
  <pre><code>provider "aws" {
    profile = "default"
    region  = "us-east-1"
  }
  
  variable "vpc_cidrs" {
    default = ["10.0.0.0/16", "10.1.0.0/16"]
  }
  
  resource "aws_vpc" "vpc" {
    for_each             = toset(var.vpc_cidrs)
    cidr_block           = each.value
    enable_dns_hostnames = true
    tags                 = { Name = "Company0${each.key}" }
  }
  </code></pre>
  
  <p>I'd like the tag Name to be <code>"Name" = "Company01"</code> and <code>"Name" = "Company02"</code> but according to terraform apply,</p>
  
  <p>I get: <code>"Name" = "Company010.0.0.0/16"</code> and <code>"Name" = "Company010.1.0.0/16"</code></p>
  
  <p>What am I missing?</p>
  
Tags: <terraform>
Title: Terraform get list index on for_each
UserDisplayName: Moshe
ThreadText: # Terraform get list index on for_each
  
  (Asked by: username_0 on 2020-04-21)
  
  Terraform newbie here. I'd like to iterate a list using `for_each`, but it seems like the key and value are the same:
  
  ```
  provider "aws" {
    profile = "default"
    region  = "us-east-1"
  }
  
  variable "vpc_cidrs" {
    default = ["10.0.0.0/16", "10.1.0.0/16"]
  }
  
  resource "aws_vpc" "vpc" {
    for_each             = toset(var.vpc_cidrs)
    cidr_block           = each.value
    enable_dns_hostnames = true
    tags                 = { Name = "Company0${each.key}" }
  }
  
  ```
  
  I'd like the tag Name to be `"Name" = "Company01"` and `"Name" = "Company02"` but according to terraform apply,
  
  I get: `"Name" = "Company010.0.0.0/16"` and `"Name" = "Company010.1.0.0/16"`
  
  What am I missing?
  
  **Tags:** terraform
  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_0 on 2020-04-21. Score: 3 | Accepted answer
  
  Found an easy solution using the [index](https://www.terraform.io/docs/configuration/functions/index.html) function:
  
  ```
  tags = { Name = "Company0${index(var.vpc_cidrs, each.value) + 1}" }
  
  ```
  
  
  ---
  
  ### Answer by username_1 on 2020-04-22. Score: 4
  
  Terraform offers two resource repetition mechanisms: [`count`](https://www.terraform.io/docs/configuration/resources.html#count-multiple-resource-instances-by-count) and [`for_each`](https://www.terraform.io/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings). The main difference between these is how Terraform will track the multiple instances they create:
  
  * When using `count`, each of the multiple instances is tracked by a number starting at 0, giving addresses like `aws_vpc.vpc[0]` and `aws_vpc.vpc[1]`.
  * When using `for_each`, each of the multiple instances is tracked by a string which could be obtained either from a key in a map or from an element in a set, giving addresses like `aws_vpc.vpc["10.0.0.0/16"]` and `aws_vpc.vpc["10.1.0.0/16"]`.
  
  The most common reason to choose `for_each` rather than `count` is to ensure that the order of whatever collection of values is driving the repetition is not significant. In your specific case, that would produce the same result regardless of whether `var.vpc_cidrs` is `["10.0.0.0/16", "10.1.0.0/16"]` or `["10.1.0.0/16", "10.0.0.0/16"]`, because the instances would be tracked by the CIDR block string and the index in the list is totally ignored.
  
  With that all said, the reason why the index isn't directly available when using `for_each` is that this would defeat the main purpose of using `for_each`: it would make the order significant again. In your specific situation, if you used the index in the tag Name then changing the order of the list would cause Terraform to plan to swap the tagging on those two VPCs:
  
  ```
   # aws_vpc.vpc["10.0.0.0/16"] will be updated in-place
   ~ resource "aws_vpc" "vpc" {
       ~ tags = {
           ~ Name = "Company01" -> "Company02"
         }
       # ...
     }
  
   # aws_vpc.vpc["10.0.0.0/16"] will be updated in-place
   ~ resource "aws_vpc" "vpc" {
       ~ tags = {
           ~ Name = "Company02" -> "Company01"
         }
       # ...
     }
  
  ```
  
  Perhaps that is fine for your case, if those numbers are just there to create some uniqueness and it doesn't matter if they get reassigned over time as CIDR blocks are added, removed and reordered in the input variable. If that's true, then we can derive a value that contains the original index and use that as part of `for_each` like this:
  
  ```
  resource "aws_vpc" "vpc" {
    for_each = { for i, b in var.vpc_cidrs : b => { index = i } }
  
    cidr_block           = each.key
    tags = {
      Name = format("Company%02d", each.value.index + 1)
    }
  }
  
  ```
  
  If you consider the position in the list to be truly significant though -- for example, if you'd want swapping two elements in the list to change the `cidr_block` values on the two existing objects rather than to re-tag them, it would be more appropriate to use `count` so that Terraform tracks them by the indices itself:
  
  ```
  resource "aws_vpc" "vpc" {
    count = length(var.vpc_cidrs)
  
    cidr_block           = var.vpc_cidrs[count.index]
    tags = {
      Name = format("Company%02d", count.index + 1)
    }
  }
  
  ```
  
  > **Comments:**
  > **username_2**: One of the best explanations there is. Figures it comes from you... :)  
  
  ---
  
  ### Answer by username_3 on 2022-04-02. Score: 0
  
  You could use without index:
  
  ```
  resource "aws_vpc" "vpc" {
    for_each = { for i, b in var.vpc_cidrs : i => b }
  
    cidr_block           = each.value
    tags = {
      Name = format("Company%02d", each.key + 1)
    }
  }
  
  ```
  
  each.key = index number
  
  
  ---
  
  