Terraform Count vs For_Each

From painful experience, my advice is: dont use count. and instead use for_each.

The reason for this is because:

  • count allows you to create and reference an instance by index number using count.index e.g. "0" If you have multiple items in a list or map and item "0" changes then all subsequent items will need to be reconfigured.
  • for_each allows you to create and reference an instance by key or value using each.key or each.value e.g. "item1" If you have multiple items in a list or map and "item1" changes then only "item1" will need to be reconfigured.

1. Terraform Count Example

# main.tf

resource "null_resource" "listvariable_count" {
    count = length(var.simplelist)
     triggers = {
        value =  var.simplelist[count.index]
    }   
}

Note below how it will create resource based on index e.g. null_resource.listvariable_count[0]


  # null_resource.listvariable_count[0] will be created
  + resource "null_resource" "listvariable_count" {
      + id       = (known after apply)
      + triggers = {
          + "value" = "item1"
        }
    }

  # null_resource.listvariable_count[1] will be created
  + resource "null_resource" "listvariable_count" {
      + id       = (known after apply)
      + triggers = {
          + "value" = "item2"
        }
    }

  # null_resource.listvariable_count[2] will be created
  + resource "null_resource" "listvariable_count" {
      + id       = (known after apply)
      + triggers = {
          + "value" = "item3"
        }
    }

If I now remove just item1 from the list. It has now determined that all 3 items in the list has changed and it now wants to replace the first 2 and destroy the 3rd!

  # null_resource.listvariable_count[0] must be replaced
-/+ resource "null_resource" "listvariable_count" {
      ~ id       = "8580541850219725515" -> (known after apply)
      ~ triggers = { # forces replacement
          ~ "value" = "item1" -> "item2"
        }
    }

  # null_resource.listvariable_count[1] must be replaced
-/+ resource "null_resource" "listvariable_count" {
      ~ id       = "6751414926727791590" -> (known after apply)
      ~ triggers = { # forces replacement
          ~ "value" = "item2" -> "item3"
        }
    }

  # null_resource.listvariable_count[2] will be destroyed
  # (because index [2] is out of range for count)
  - resource "null_resource" "listvariable_count" {
      - id       = "2150514161108105462" -> null
      - triggers = {
          - "value" = "item3"
        } -> null
    }

2. Terraform For_each Example.

# main.tf

resource "null_resource" "listvariable_for_each" {
    for_each = {for v in var.simplelist: v => v}
     triggers = {
        value =  each.value
    }   
}

Note below how it will create resource based on key e.g. null_resource.listvariable_for_each["item1"]


  # null_resource.listvariable_for_each["item1"] will be created
  + resource "null_resource" "listvariable_for_each" {
      + id       = (known after apply)
      + triggers = {
          + "value" = "item1"
        }
    }

  # null_resource.listvariable_for_each["item2"] will be created
  + resource "null_resource" "listvariable_for_each" {
      + id       = (known after apply)
      + triggers = {
          + "value" = "item2"
        }
    }

  # null_resource.listvariable_for_each["item3"] will be created
  + resource "null_resource" "listvariable_for_each" {
      + id       = (known after apply)
      + triggers = {
          + "value" = "item3"
        }
    }

If I now remove item1 from the list. It correctly identifies that only "item1" has been changed so it takes the specific action to destroy it. Also note that it tells you why it is going to perform this action e.g. (because key ["item1"] is not in for_each map)

  # null_resource.listvariable_for_each["item1"] will be destroyed
  # (because key ["item1"] is not in for_each map)
  - resource "null_resource" "listvariable_for_each" {
      - id       = "162396972649776379" -> null
      - triggers = {
          - "value" = "item1"
        } -> null
    }