Accidently nuked half of some resources and broke DNS (yes, it is in fact always DNS). One of the first things I learned and is on a lot of guides for terraform is how count works. It’s one of the meta-arguments you can use with most resources, others are

1
2
3
4
5
depends_on 
count
for_each
provider / providers
lifecycle

Here’s an example for count before I show my oops.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
variable "names" {
  default = ["alice", "bob", "carol"]
}

resource "aws_instance" "web" {
  count         = length(var.names)
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = var.names[count.index]
  }
}

Remove "bob"default = ["alice", "carol"]. You’ll see this in your terraform run of web[1] transitioning.

1
  ~ Name = "bob" -> "carol"

carol shifts from index 2 → 1, so Terraform modifies the bob instance to become carol, and destroys the old carol. Two changes instead of one.

count is very quick and easy to use but honestly I avoided it. If I read of a feature that has to be used with extra considerations, I’d rather use the pattern that doesn’t let me screw up if my coffee has fully kicked in.


In my case, I added to middle of an array in a variable but the implementation logic was a count instead of a for_each.

Here’s an implementation that guarentess uniqness in the array to avoid collisions and doesn’t care about order.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# Before (vulnerable — index shuffle on any list change)
resource "aws_instance" "web" {
  count         = length(var.names)
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = var.names[count.index]
  }
}

# After (safe — each instance is an independent resource)
resource "aws_instance" "web" {
  for_each      = toset(var.instances)
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = each.key
  }
}

Even better is that with the first method you access the resource like aws_instance.web[0] but with the 2nd you get a much more descriptive and assuring aws_instance.web["bob"]