Terraform Tutorial · Terraform Language · Lesson 13 of 25

Terraform count and for_each

Create several copies of a resource with count or for_each, and learn why for_each is usually the safer choice.

count

count creates N copies, numbered from 0, addressed as aws_instance.web[0], [1], …

resource "aws_instance" "web" {
  count         = 3
  ami           = var.ami
  instance_type = "t3.micro"
  tags = { Name = "web-${count.index}" }
}

count = var.enabled ? 1 : 0 is the classic way to create a resource conditionally.

for_each

for_each creates one copy per map key or set element, addressed by key: aws_s3_bucket.this["logs"].

for_each over a map
terraform {
  required_providers {
    local = { source = "hashicorp/local", version = "~> 2.5" }
  }
}

resource "local_file" "env" {
  for_each = {
    dev  = "debug=true"
    prod = "debug=false"
  }
  filename = "${path.module}/${each.key}.env"
  content  = each.value
}

Output

Terraform will perform the following actions:

  # local_file.env["dev"] will be created
  + resource "local_file" "env" {
      + content              = "debug=true"
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "./dev.env"
      + id                   = (known after apply)
    }

  # local_file.env["prod"] will be created
  + resource "local_file" "env" {
      + content              = "debug=false"
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "./prod.env"
      + id                   = (known after apply)
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Run this on your computer — see “Get Started” for setup.

Why for_each is usually better

With count, copies are identified by position. Remove the first item of a list and every later item shifts, so Terraform destroys and re-creates them. With for_each, copies are identified by key, so removing one item affects only that item.

Positions vs keys
locals {
  names = ["alpha", "beta", "gamma"]
}

output "count_style_addresses" {
  value = [for i, n in local.names : "server[${i}] = ${n}"]
}

output "for_each_style_addresses" {
  value = [for n in local.names : "server[\"${n}\"]"]
}

Output

count_style_addresses = [
  "server[0] = alpha",
  "server[1] = beta",
  "server[2] = gamma",
]
for_each_style_addresses = [
  "server[\"alpha\"]",
  "server[\"beta\"]",
  "server[\"gamma\"]",
]

Run this on your computer — see “Get Started” for setup.

Test yourself

You remove the first of three servers created with count. What happens to the other two?

  1. Nothing
  2. They are replaced, because their indexes shift
  3. They are imported
  4. Terraform refuses to plan
Show answer

Answer: They are replaced, because their indexes shift