Skip to main content
Terraform intermediate Lesson 7 of 11

Terraform `count` and `for_each` (repeat resources safely)

Learn when to use `count` vs `for_each`, how Terraform addresses multiple instances, and practical examples.

Terraform needs to manage multiple similar resources: users, subnets, security rules, etc.

Two meta-arguments do this:

  • count (index-based)
  • for_each (key-based)

Learning outcomes

After this tutorial you can:

  • decide between count and for_each
  • reference instances correctly
  • avoid common plan/apply surprises when keys change

1) count (index-based)

Example: create N resources

resource "aws_s3_bucket" "buckets" {
  count = 3

  bucket = "my-unique-bucket-${count.index}-12345"
}

References:

  • aws_s3_bucket.buckets[count.index]
  • aws_s3_bucket.buckets[*].bucket (splat syntax)

When count can be risky

If the middle element changes, Terraform may re-index and re-create resources.

2) for_each (map/set-based)

for_each works with:

  • maps (keys become instance keys)
  • sets (values are keys when values are unique)

Example: map keyed resources

locals {
  services = {
    api    = "v1"
    worker = "v2"
  }
}

resource "aws_s3_bucket" "service_buckets" {
  for_each = local.services

  bucket = "my-unique-${each.key}-${each.value}-12345"
}

References:

  • aws_s3_bucket.service_buckets["api"].bucket
  • aws_s3_bucket.service_buckets[each.key].bucket

3) for_each with sets

If you have a list of unique names:

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

resource "null_resource" "example" {
  for_each = toset(local.names)

  triggers = {
    name = each.value
  }
}

4) Choosing between them

Prefer for_each when:

  • you have an identity (name/id) per instance
  • you want stable mapping across changes
  • you want to avoid index-based churn

Prefer count when:

  • you only need simple repetition
  • order/index is stable for your use case

5) Example: environment-specific naming

variable "environment" {
  type    = string
  default = "dev"
}

locals {
  cidrs = {
    subnet_a = "10.0.1.0/24"
    subnet_b = "10.0.2.0/24"
  }
}

resource "null_resource" "subnets" {
  for_each = local.cidrs

  triggers = {
    env  = var.environment
    cidr = each.value
  }
}

6) Cleanup reminder

Repeat resources created with count/for_each will be destroyed based on state.

Use:

terraform destroy

Frequently Asked Questions

When should I use `for_each` instead of `count`?
Prefer `for_each` when instances are keyed by something stable (names/maps). `count` is best for simple ordered repetition where index changes are acceptable.