interview-prep

Crisp answer: count creates N identical copies of a resource indexed numerically. for_each creates one resource per element of a map or set, keyed by the element. Prefer for_each for anything that might have items removed — it avoids index shifting.

count:

resource "aws_instance" "web" {
  count         = 3
  ami           = "ami-0abc123"
  instance_type = "t3.micro"
  tags = {
    Name = "web-${count.index}"   # web-0, web-1, web-2
  }
}

# References:
# aws_instance.web[0].id
# aws_instance.web[1].private_ip
# aws_instance.web[*].id   (all IDs as a list)

# Conditional creation (count = 0 means don't create)
resource "aws_cloudwatch_log_group" "app" {
  count = var.enable_logging ? 1 : 0
  name  = "/app/logs"
}
# Reference: aws_cloudwatch_log_group.app[0].arn (if it exists)
# Or use: one(aws_cloudwatch_log_group.app[*].arn)

The count index shifting problem:

# var.users = ["alice", "bob", "carol"]
resource "aws_iam_user" "users" {
  count = length(var.users)
  name  = var.users[count.index]
}
# Creates: users[0]=alice, users[1]=bob, users[2]=carol

# Remove "bob" from var.users = ["alice", "carol"]
# Terraform sees:
# users[0]=alice (unchanged)
# users[1]=carol (was "bob" — must destroy bob, create carol)  ← unwanted
# users[2] must be destroyed  ← unwanted

for_each — the solution:

resource "aws_iam_user" "users" {
  for_each = toset(var.users)   # convert list to set
  name     = each.key
}
# Creates: users["alice"], users["bob"], users["carol"]

# Remove "bob": only users["bob"] is destroyed. alice and carol untouched.

# Map example:
resource "aws_subnet" "private" {
  for_each = {
    "eu-west-2a" = "10.0.1.0/24"
    "eu-west-2b" = "10.0.2.0/24"
  }
  vpc_id            = aws_vpc.main.id
  availability_zone = each.key    # "eu-west-2a"
  cidr_block        = each.value  # "10.0.1.0/24"
  tags = {
    Name = "private-${each.key}"
  }
}
# References: aws_subnet.private["eu-west-2a"].id

Rules:

  • Cannot use both count and for_each on the same resource
  • for_each values must be known at plan time (no dynamic unknown values)
  • count can use a simple number computed at plan time

What to say in the interview:

"count gives you N copies indexed 0 to N-1. for_each gives you one resource per element of a map or set, keyed by the element. The reason to prefer for_each: if you use count with a list and remove an element from the middle, all resources after that index get shifted and Terraform destroys and recreates them unnecessarily. for_each uses stable string keys so removing one element only affects that one resource. I use count for simple conditional creation (count = 0 or 1) and for_each for everything else that iterates over a collection."


My notes