Learning objectives
By the end of this module, you should be able to:
- Work with lists, sets, maps, for expressions and conditionals.
- Choose between count and for_each.
- Explain why stable keys reduce address churn.
Expressions transform values
Terraform expressions combine literals, references, operators, functions, conditionals and for expressions. Collection transformations are central to reusable infrastructure.
count creates numeric instances
count is concise when instances are truly interchangeable and positional. Removing an item from the middle of a positional list can shift indexes and cause surprising address changes.
for_each uses stable keys
for_each accepts a map or set of strings. Keys become part of resource addresses, making identity explicit and usually safer for named infrastructure.
Worked examples
See the idea in practice.
Stable service instances
variable "services" {
type = map(number)
default = {
api = 2
worker = 1
}
}
resource "terraform_data" "service" {
for_each = var.services
input = {
name = each.key
replicas = each.value
}
}
- Addresses remain keyed by api and worker rather than numeric positions.
Hands-on lab
Lab — Model stable instances with for_each
Goal: Create keyed instances and derive a map output with a for expression.
STEP 1Write keyed configuration
mkdir -p ~/gnu-terraform-labs/module04 && cd ~/gnu-terraform-labs/module04
cat > main.tf <<'EOF'
variable "services" {
type = map(number)
default = {
api = 2
worker = 1
jobs = 1
}
}
resource "terraform_data" "service" {
for_each = var.services
input = {
name = each.key
replicas = each.value
}
}
output "replicas" {
value = { for k, v in terraform_data.service : k => v.output.replicas }
}
EOF
STEP 2Apply
terraform init
terraform apply -auto-approve
STEP 3Inspect addresses
terraform state list
STEP 4Inspect derived map
terraform output replicas
Verify
- Three instances exist with string keys.
- The output maps each service key to its replica value.
Expected outcome
- You can choose stable keys instead of relying on positional identity.
If it fails
- for_each keys must be known before apply.
- Convert a list of unique strings with toset when only membership matters.
Real-world connectionStable instance identity reduces accidental replacement during list reordering and makes state addresses easier to reason about.
Avoid these traps
Common mistakes
- Using count for named objects whose identity should survive reordering.
- Using duplicate values in a set and expecting duplicates to remain.
- Trying to derive for_each keys from values unknown until apply.
Knowledge check
Can you explain it without looking back?
Open each answer only after you have tried to answer the question yourself.
1When is for_each usually preferable to count?
When instances have meaningful stable keys or names.
2What becomes part of a for_each resource address?
The map or set key.
3Why can count be brittle with reordered lists?
Numeric indexes can shift, changing which address maps to which intended object.