TFNFR7 - Count & for_each Use
ID: TFNFR7 - Category: Code Style - count & for_each Use
We can use count and for_each to deploy multiple resources, but using count with an ordered collection can create an index anti-pattern where removing one item unexpectedly changes other resource addresses.
You can use count to create some kind of resources under certain conditions, for example:
resource "azapi_resource" "network_security_group" {
count = local.create_new_security_group ? 1 : 0
type = "Microsoft.Network/networkSecurityGroups@2023-11-01"
name = coalesce(var.new_network_security_group_name, "${var.subnet_name}-nsg")
parent_id = var.parent_id
location = local.location
tags = var.new_network_security_group_tags
body = {
properties = {}
}
response_export_values = []
}The module’s owners MUST use map(xxx) or set(xxx) as resource’s for_each collection, the map’s key or set’s element MUST be static literals.
Good example:
resource "azapi_resource" "subnet_pair" {
for_each = var.subnet_map // `map(string)`, when user call this module, it could be: `{ "subnet0": "subnet0" }`, or `{ "subnet0": azapi_resource.subnet0.name }`
type = "Microsoft.Network/virtualNetworks/subnets@2023-11-01"
name = "${each.value}-pair"
parent_id = azapi_resource.virtual_network.id
body = {
properties = {
addressPrefixes = ["10.0.1.0/24"]
}
}
response_export_values = []
}Bad example:
resource "azapi_resource" "subnet_pair" {
for_each = var.subnet_name_set // `set(string)`, when user use `toset([azapi_resource.subnet0.name])`, it would cause an error.
type = "Microsoft.Network/virtualNetworks/subnets@2023-11-01"
name = "${each.value}-pair"
parent_id = azapi_resource.virtual_network.id
body = {
properties = {
addressPrefixes = ["10.0.1.0/24"]
}
}
response_export_values = []
}