🧩 For-Each in Terraform: Iterate Over Maps/Sets to Create Resources


In the world of Infrastructure as Code (IaC), Terraform is the gold standard for automating cloud resource management. While Terraform’s count argument helps create multiple identical resources, sometimes you need to create multiple unique resources — each with different names, configurations, or attributes.

That’s where for_each comes in.


🔹 What is for_each in Terraform?

The for_each meta-argument allows you to loop over maps or sets to create multiple distinct resources, each identified by a unique key.

Unlike count, which uses numerical indices (0,1,2…), for_each uses keys or values from maps or sets.

This gives you more control, readability, and flexibility in your Terraform configurations.


⚙️ Basic Syntax

resource "aws_instance" "server" {
for_each = toset(["web", "app", "db"])
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = each.key
}
}

🔍 Explanation:

  • Terraform will create three EC2 instances:

    • server["web"]
    • server["app"]
    • server["db"]
  • each.key gives access to the key of the current item.

  • each.value gives access to the value (when using maps).


🔹 Why Use for_each?

When each resource requires unique attributes (like names or tags), for_each is superior to count. It makes the code:

  • More descriptive (uses names instead of numbers)
  • Easier to maintain
  • Less error-prone when items change

🔹 Key Concepts of for_each

ConceptDescription
Data StructuresWorks with maps and sets
Key-based IdentificationEach resource is identified by a key
Stable Resource MappingAvoids resource recreation when order changes
Dynamic ConfigurationUse variables to generate unique resources

🧭 ** How for_each Works**

Terraform Configuration

for_each = tosetweb, app, db

Create web instance

Create app instance

Create db instance

Resources Deployed


🧱 Example 1: Create Multiple EC2 Instances Using for_each

Terraform Code Example

provider "aws" {
region = "us-east-1"
}
locals {
instances = {
web = "t2.micro"
app = "t2.small"
db = "t2.medium"
}
}
resource "aws_instance" "server" {
for_each = local.instances
ami = "ami-0c55b159cbfafe1f0"
instance_type = each.value
tags = {
Name = each.key
}
}

🧩 Explanation:

  • We defined a map (local.instances) containing roles and instance types.

  • Terraform creates:

    • web → t2.micro
    • app → t2.small
    • db → t2.medium
  • each.key → “web”, “app”, “db”

  • each.value → corresponding instance type

🧠 Memory Trick:

“Each key gets its own machine — that’s the power of for_each!”


🧱 Example 2: Creating Multiple S3 Buckets from a List

Terraform Code Example

variable "buckets" {
type = set(string)
default = ["logs-bucket", "images-bucket", "backup-bucket"]
}
resource "aws_s3_bucket" "storage" {
for_each = var.buckets
bucket = each.value
acl = "private"
}

🧩 Explanation:

  • for_each iterates over the set of bucket names.

  • Terraform creates three separate buckets with unique names.

  • Each resource is referenced as:

    • aws_s3_bucket.storage["logs-bucket"]
    • aws_s3_bucket.storage["images-bucket"]
    • aws_s3_bucket.storage["backup-bucket"]

🧠 Memory Trick:

“Sets create buckets — each name unique and clear!”


🧱 Example 3: Using for_each with Modules

Terraform Code Example

variable "servers" {
type = map(object({
instance_type = string
environment = string
}))
default = {
dev = { instance_type = "t2.micro", environment = "dev" }
prod = { instance_type = "t2.medium", environment = "prod" }
}
}
module "ec2_instance" {
source = "./modules/ec2"
for_each = var.servers
instance_type = each.value.instance_type
environment = each.value.environment
}

🧩 Explanation:

  • for_each allows you to reuse a module multiple times with different parameters.

  • Two modules are created:

    • module.ec2_instance["dev"]
    • module.ec2_instance["prod"]

🧠 Memory Tip:

“Each environment, one module — modularity with for_each!”


🧭 ** Module Iteration**

for_each = var.servers

Module ec2_instance dev

Module ec2_instance prod

Deployed EC2 for Dev

Deployed EC2 for Prod


🔹 Comparing count vs for_each

Featurecountfor_each
Input TypeNumberMap or Set
ReferenceUses index ([0], [1])Uses key (["name"])
When to UseIdentical resourcesUnique resource attributes
StabilityIndex order dependentKey-based, stable mapping
FlexibilityLimitedVery flexible

Example Comparison:

Using count:

count = 3
tags = { Name = "Server-${count.index}" }

Using for_each:

for_each = toset(["web", "app", "db"])
tags = { Name = each.key }

🔹 Understanding each.key and each.value

TermDescriptionExample
each.keyRefers to the key of the current item“web”
each.valueRefers to the value of the current item“t2.micro”

Example:

for_each = {
web = "t2.micro"
db = "t2.medium"
}
  • each.key = “web” / “db”
  • each.value = “t2.micro” / “t2.medium”

🔹 How to Remember for_each for Exams

🎓 Mnemonic: “E.A.C.H.”

LetterMeaning
EEvery resource gets its key
AAvoids index confusion
CCreates unique configurations
HHandy for maps and sets

💡 Phrase:

“For each key, Terraform builds with ease!”


🔹 Why for_each Is Important

ReasonDescription
Improved FlexibilityHandles complex resource mapping easily
ReadabilityUses human-readable keys instead of numbers
Reduced ErrorsKeys remain stable even if order changes
Scalable DesignPerfect for multi-environment deployments
Interview-Ready ConceptCommonly asked Terraform question

🔹 When to Use for_each

✅ When resources differ slightly (different names or settings) ✅ When working with maps or sets ✅ When you need stable references ✅ When you want clarity in resource naming


🔹 Common Mistakes

MistakeDescriptionSolution
Using listsfor_each only works with sets/mapsConvert using toset()
Duplicate keysCauses errorsEnsure unique keys
Mixing with countNot allowedUse one per resource
Changing keysDestroys and recreates resourcesKeep keys stable

🧭 ** for_each Execution Flow**

Read Terraform Config

Detect for_each Meta-Argument

Iterate Over Map or Set

Create Resource for each.key

Provision Resources


🔹 Best Practices

✅ Use maps when resources have different configurations. ✅ Use sets for identical resources with unique names. ✅ Always give meaningful keys for readability. ✅ Avoid changing map keys in production. ✅ Combine for_each with modules for scalable design.


🔹 Advanced Use Case: Dynamic Security Groups

Terraform Code Example

variable "security_rules" {
type = map(object({
from_port = number
to_port = number
protocol = string
}))
default = {
ssh = { from_port = 22, to_port = 22, protocol = "tcp" }
http = { from_port = 80, to_port = 80, protocol = "tcp" }
}
}
resource "aws_security_group_rule" "rules" {
for_each = var.security_rules
type = "ingress"
from_port = each.value.from_port
to_port = each.value.to_port
protocol = each.value.protocol
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.main.id
}

🧩 Explanation:

  • Each key represents a rule type (ssh, http).
  • Terraform creates one ingress rule per key.

🔹 ** Security Rules Example**

for_each = var.security_rules

ssh Rule

http Rule

Security Group Updated


🔹 Interview Preparation

Common Questions:

  1. What is the difference between count and for_each?
  2. Can you use for_each with modules?
  3. What are each.key and each.value?
  4. What happens if you change a key in for_each?
  5. When should you prefer for_each over count?

Tips to Answer:

  • Emphasize key-based resource creation.
  • Highlight stability when list order changes.
  • Mention that maps and sets are the input types.

🔹 How to Study for_each for Exams

✅ Write simple examples (EC2, S3, module-based). ✅ Understand the difference between map vs set. ✅ Practice referencing resources with keys. ✅ Use terraform plan to visualize. ✅ Remember: for_each = key-based looping.


🔹 Real-World Use Cases

ScenarioDescription
Multi-environment deploymentCreate different configurations for dev/prod
Security rulesGenerate firewall rules dynamically
S3 bucketsCreate multiple named buckets
IAM roles/policiesAssign roles per environment
DNS recordsAdd multiple route entries dynamically

🔹 ** for_each in Real World**

for_each = environments

Dev Resources

Staging Resources

Prod Resources


🔹 Quick Recap Table

FeatureDescriptionExample
PurposeCreate multiple resources from maps/setsfor_each = toset([...])
ReferenceKey-based accesseach.key, each.value
FlexibilityHighWorks with complex structures
StabilityStableOrder-independent
AlternativecountIndex-based creation

🔹 Mnemonic Recap

F.O.R.E.A.C.H. → Flexible Object Resource: Each Accesses Custom Handling

💡 Or simply remember:

“Each key, its own destiny!”


🔹 Why It’s Important to Learn for_each

  1. Core Terraform Concept – Frequently used in real-world IaC setups.
  2. Saves Time – Avoids code duplication.
  3. Scalable Infrastructure – Handles complex cloud environments easily.
  4. Exam Relevance – Often appears in Terraform certification questions.
  5. Interview Edge – Shows mastery of Terraform’s dynamic resource creation.

🔹 Conclusion

Terraform’s for_each is a vital tool for building dynamic, flexible, and efficient infrastructure. By iterating over maps or sets, you can create uniquely configured resources while keeping your code clean and DRY (Don’t Repeat Yourself).

It’s not just about saving lines of code — it’s about building infrastructure that adapts, scales, and evolves with your organization’s needs.

💡 Final Thought: “For every key, a resource to be — that’s the power of for_each in Terraform.”