• 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 and instance2 are unique keys that Terraform uses to identify resources.

  • If you remove instance2, Terraform only destroys that specific resource without touching instance1.

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:

  1. All resources are identical.

  2. The number of resources is fixed or rarely changes.

  3. 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:

  1. Resources need unique properties or identifiers.

  2. The number of resources may change dynamically.

  3. 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

or to participate.