Define a variable of type map(object(...)): variable "environments" { type = map(object({ region = string; instance_type = string; min_capacity = number })) }
Populate the variable in terraform.tfvars or via a .tfvars file per environment: environments = { staging = { region = "us-east-1"; instance_type = "t3.medium"; min_capacity = 1 }; prod = { region = "us-east-1"; instance_type = "m6i.large"; min_capacity = 3 } }
Use for_each in the module call: module "env" { for_each = var.environments; source = "./modules/app-environment"; region = each.value.region; instance_type = each.value.instance_type }
Inside the child module, use each.key as a name prefix for resources to avoid naming collisions: name = "${each.key}-cluster"
Run terraform plan and confirm two module instances appear: module.env["staging"] and module.env["prod"] with their respective configurations
To add a new environment, add it to the map variable and run terraform plan / apply — only the new environment's resources are created, existing environments are unaffected
Known gotchas
Removing an environment key from the map causes Terraform to plan deletion of all resources in that module instance; use lifecycle.prevent_destroy on critical resources to guard against accidental removal
for_each on modules requires Terraform 0.13+; the module instance addresses use string keys (module.env["prod"]), not integer indices as with count — ensure terraform state addresses in import blocks or moved blocks use the correct string-keyed format
If the map variable is computed (derived from a data source or resource attribute), Terraform may report that the for_each value depends on resource attributes that cannot be determined until apply — use a static or input-variable-derived map where possible to avoid this plan error
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp