Terraform
Basics & Fundamentals
- Infrastructure as Code (IaC)
- Declarative Syntax in IaC
- Terraform Configuration Files
- Terraform CLI
- Terraform Init
- Terraform Plan
- Terraform Apply
- Terraform Destroy
Providers & Resources
Variables & Outputs
- Input Variables
- Variable Types
- Default Values
- Environment Variables
- Output Values
- Variable Validation
State Management
- Terraform State File
- Terraform Remote State
- Terraform State Locking
- Terraform Drift Detection
- Terraform Refresh
- Terraform Import
Modules (Reusability)
- Terraform Modules
- Terraform Public Modules
- Terraform local modules
- Terraform Module Versioning
- Terraform Nested Modules
Provisioners & Lifecycle
🧩 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
Concept | Description |
---|---|
Data Structures | Works with maps and sets |
Key-based Identification | Each resource is identified by a key |
Stable Resource Mapping | Avoids resource recreation when order changes |
Dynamic Configuration | Use variables to generate unique resources |
🧭 ** How for_each
Works**
🧱 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.microapp
→ t2.smalldb
→ 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**
🔹 Comparing count
vs for_each
Feature | count | for_each |
---|---|---|
Input Type | Number | Map or Set |
Reference | Uses index ([0] , [1] ) | Uses key (["name"] ) |
When to Use | Identical resources | Unique resource attributes |
Stability | Index order dependent | Key-based, stable mapping |
Flexibility | Limited | Very flexible |
Example Comparison:
Using count
:
count = 3tags = { Name = "Server-${count.index}" }
Using for_each
:
for_each = toset(["web", "app", "db"])tags = { Name = each.key }
🔹 Understanding each.key
and each.value
Term | Description | Example |
---|---|---|
each.key | Refers to the key of the current item | “web” |
each.value | Refers 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.”
Letter | Meaning |
---|---|
E | Every resource gets its key |
A | Avoids index confusion |
C | Creates unique configurations |
H | Handy for maps and sets |
💡 Phrase:
“For each key, Terraform builds with ease!”
🔹 Why for_each
Is Important
Reason | Description |
---|---|
Improved Flexibility | Handles complex resource mapping easily |
Readability | Uses human-readable keys instead of numbers |
Reduced Errors | Keys remain stable even if order changes |
Scalable Design | Perfect for multi-environment deployments |
Interview-Ready Concept | Commonly 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
Mistake | Description | Solution |
---|---|---|
Using lists | for_each only works with sets/maps | Convert using toset() |
Duplicate keys | Causes errors | Ensure unique keys |
Mixing with count | Not allowed | Use one per resource |
Changing keys | Destroys and recreates resources | Keep keys stable |
🧭 ** for_each Execution Flow**
🔹 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**
🔹 Interview Preparation
Common Questions:
- What is the difference between
count
andfor_each
? - Can you use
for_each
with modules? - What are
each.key
andeach.value
? - What happens if you change a key in
for_each
? - When should you prefer
for_each
overcount
?
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
Scenario | Description |
---|---|
Multi-environment deployment | Create different configurations for dev/prod |
Security rules | Generate firewall rules dynamically |
S3 buckets | Create multiple named buckets |
IAM roles/policies | Assign roles per environment |
DNS records | Add multiple route entries dynamically |
🔹 ** for_each in Real World**
🔹 Quick Recap Table
Feature | Description | Example |
---|---|---|
Purpose | Create multiple resources from maps/sets | for_each = toset([...]) |
Reference | Key-based access | each.key , each.value |
Flexibility | High | Works with complex structures |
Stability | Stable | Order-independent |
Alternative | count | Index-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
- Core Terraform Concept – Frequently used in real-world IaC setups.
- Saves Time – Avoids code duplication.
- Scalable Infrastructure – Handles complex cloud environments easily.
- Exam Relevance – Often appears in Terraform certification questions.
- 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.”