Problem
When you modify the key of a map used in a for_each argument, Terraform destroys and recreates the associated resource instead of updating it in-place.
Consider the following configuration where the resource's input attribute is derived from each.key.
locals {
names = {
"my_index" = { name = "my_name" }
}
}
resource "terraform_data" "example" {
for_each = local.names
input = each.key
}If you change the map key from my_index to my_index_changed, Terraform produces a plan to destroy the existing resource and create a new one.
$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
- destroy
Terraform will perform the following actions:
# terraform_data.example["my_index"] will be destroyed
# (because key ["my_index"] is not in for_each map)
- resource "terraform_data" "example" {
- id = "9012385b-25d6-5fc0-403e-7cbb4291fe2d" -> null
- input = "my_index" -> null
- output = "my_index" -> null
}
# terraform_data.example["my_index_changed"] will be created
+ resource "terraform_data" "example" {
+ id = (known after apply)
+ input = "my_index_changed"
+ output = (known after apply)
}
Plan: 1 to add, 0 to change, 1 to destroy.Cause
Terraform uses the keys of the map provided to for_each to identify and track each resource instance in the state file. When you change a key (e.g., from my_index to my_index_changed), Terraform interprets this as two separate actions:
- The resource instance associated with the old key (
my_index) no longer exists in the configuration and must be destroyed. - The resource instance associated with the new key (
my_index_changed) does not exist in the state file and must be created.
This behavior is intentional, as the key serves as the resource's unique identifier within the for_each block.
Solution
To allow for in-place updates, you should use stable, unique keys in your for_each map and reference the map's values for attributes that you expect to change. The keys should not contain the data that you intend to modify.
Update the configuration to reference each.value.name for the input attribute.
locals {
names = {
"my_index" = { name = "my_name" }
}
}
resource "terraform_data" "example" {
for_each = local.names
input = each.value.name
}Now, if you modify the name value within the map (e.g., from my_name to my_name_changed) while keeping the key my_index the same, Terraform will correctly plan an in-place update.
$ terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# terraform_data.example["my_index"] will be updated in-place
~ resource "terraform_data" "example" {
id = "9012385b-25d6-5fc0-403e-7cbb4291fe2d"
~ input = "my_name" -> "my_name_changed"
~ output = "my_name" -> (known after apply)
# (1 unchanged attribute hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.By keeping the key stable, you signal to Terraform that it is the same resource instance, allowing for modifications to its attributes without forcing a replacement.
Additional Information
- For more details, refer to the official documentation on The
for_eachMeta-Argument.