- Cloud Cycle
- Posts
- Understanding count vs for_each in Terraform: A Detailed Guide with Practical Examples
Understanding count vs for_each in Terraform: A Detailed Guide with Practical Examples
When working with Terraform, efficiently managing multiple resources is a common requirement. Terraform provides two powerful meta-arguments for this purpose: count
and for_each
. While both are used to create multiple instances of a resource dynamically, they differ significantly in functionality, behavior, and use cases.
What is count
in Terraform?
The count
meta-argument creates a specified number of resource instances. It is simple to use when you know the exact number of resources required.
Example: Using count
to create EC2 instances
variable "instances" {
type = list(string)
default = ["one", "two", "three"]
}
resource "aws_instance" "example" {
count = var.instances
ami = "ami-12345678"
instance_type = "t2.micro"
}
In this example, Terraform creates three identical EC2 instances. You can reference these instances using zero-based indices:
aws_instance.example[0]
aws_instance.example[1]
aws_instance.example[2]
This is straightforward for creating resources when every instance is identical and the number of instances is fixed.
The Problem with count
: Re-Indexing Issues
The main challenge with count
arises when you modify the number of instances. For example, if we remove the second value in the list, Terraform doesn’t simply remove the instance number two. Instead, it re-indexes the remaining instances.
Example: Reducing the count
variable "instances" {
type = list(string)
default = ["one", "three"]
}
resource "aws_instance" "example" {
count = var.instances
ami = "ami-12345678"
instance_type = "t2.micro"
}
This may seem harmless, but here’s what happens:
Terraform destroys the instance
aws_instance.example[1]
.Terraform re-indexes the remaining instances, causing
aws_instance.example[2]
to be replaced.
This can lead to downtime and loss of data, especially in production environments where resource identities are critical.
What is for_each
in Terraform?
The for_each
meta-argument provides more flexibility by iterating over a map or set of values. Each element in the map or set becomes a unique resource instance, identified by its key.
Example: Using for_each
to create EC2 instances
resource "aws_instance" "example" {
for_each = {
instance1 = "ami-12345678"
instance2 = "ami-87654321"
}
ami = each.value
instance_type = "t2.micro"
}
In this case:
instance1
andinstance2
are unique keys that Terraform uses to identify resources.If you remove
instance2
, Terraform only destroys that specific resource without touchinginstance1
.
This behavior makes for_each
ideal for managing resources with unique properties or identifiers.
Key Differences Between count
and for_each
Feature | count | for_each |
---|---|---|
Input Type | Number | Map or Set |
Resource Identity | Based on numeric index | Based on unique keys |
Resource Updates | Re-indexing may recreate resources | Updates only specific resources |
Flexibility | Less flexible | Highly flexible |
When to Use count
count
is a good choice when:
All resources are identical.
The number of resources is fixed or rarely changes.
Re-indexing won’t cause issues, such as in development environments.
Example: Creating Fixed Security Groups
resource "aws_security_group" "example" {
count = 2
name = "example-group-${count.index}"
description = "Example Security Group"
}
This creates two identical security groups named example-group-0
and example-group-1
.
When to Use for_each
for_each
is better when:
Resources need unique properties or identifiers.
The number of resources may change dynamically.
Re-indexing must be avoided.
Example 1: Creating EC2 Instances with Unique Names
variable "instances" {
default = {
instance1 = "ami-12345678"
instance2 = "ami-87654321"
}
}
resource "aws_instance" "example" {
for_each = var.instances
ami = each.value
instance_type = "t2.micro"
tags = {
Name = each.key
}
}
Here, each instance gets a unique name based on its key, such as instance1
or instance2
. Removing one key won’t affect the other instances.
Example 2: Using a Set with for_each
You can also use a set with for_each
. Unlike maps, sets don’t have key-value pairs but are great for simple lists of unique values.
variable "tags" {
default = ["web", "db", "cache"]
}
resource "aws_security_group" "example" {
for_each = toset(var.tags)
name = "sg-${each.key}"
}
This creates three security groups named sg-web
, sg-db
, and sg-cache
.
Dynamic Resource Creation: A Practical Comparison
Let’s say you want to create resources dynamically based on a variable. Here’s how you would do it with count
and for_each
:
With count
variable "instances" {
default = ["ami-12345678", "ami-87654321"]
}
resource "aws_instance" "example" {
count = length(var.instances)
ami = var.instances[count.index]
instance_type = "t2.micro"
}
Here, resources are created based on the length of the list. But if you remove an AMI from the list, all subsequent resources are re-indexed, leading to potential disruptions.
With for_each
variable "instances" {
default = {
instance1 = "ami-12345678"
instance2 = "ami-87654321"
}
}
resource "aws_instance" "example" {
for_each = var.instances
ami = each.value
instance_type = "t2.micro"
}
With for_each
, removing instance2
won’t affect instance1
. Terraform knows which resource corresponds to each key.
Conclusion: Choosing Between count
and for_each
Choosing between count
and for_each
depends on your use case:
Use
count
for simple, identical resources with predictable numbers.Use
for_each
for more complex scenarios where each resource needs unique properties or when avoiding re-indexing is crucial.
By understanding these differences, you can write cleaner, more predictable Terraform configurations and avoid the pitfalls of re-indexing or unnecessary resource destruction.
Terraform is all about automation, and choosing the right tool for the job is key to building robust, scalable infrastructure.
What challenges have you faced with count
or for_each
? Let me know in the comments below!
Reply