count & for_each

terraform-learning Hands-on Terraform configs, modules, and practice projects on GitHub.

count & for_each

count and for_each are used to create multiple instances of a resource from a single resource block.


1. count

Use count when you want to create multiple similar resources based on a number.

Without count:

resource "aws_instance" "server1" {
  ami           = "ami-123456"
  instance_type = "t3.micro"
}

resource "aws_instance" "server2" {
  ami           = "ami-123456"
  instance_type = "t3.micro"
}

With count:

resource "aws_instance" "server" {
  count = 2

  ami           = "ami-123456"
  instance_type = "t3.micro"
}

Terraform creates:

aws_instance.server[0]
aws_instance.server[1]

2. count.index

count.index gives the index of the current resource.

It starts from 0.

resource "aws_instance" "server" {
  count = 3

  ami           = "ami-123456"
  instance_type = "t3.micro"

  tags = {
    Name = "server-${count.index}"
  }
}

Terraform creates:

server-0
server-1
server-2

You can also make it start visually from 1:

Name = "server-${count.index + 1}"

Result:

server-1
server-2
server-3

3. count with a List

count is often combined with length().

variable "subnet_cidrs" {
  default = [
    "10.0.1.0/24",
    "10.0.2.0/24"
  ]
}

Then:

resource "aws_subnet" "public" {
  count = length(var.subnet_cidrs)

  vpc_id     = aws_vpc.main.id
  cidr_block = var.subnet_cidrs[count.index]
}

Flow:

var.subnet_cidrs
       │
       ├── [0] → 10.0.1.0/24
       └── [1] → 10.0.2.0/24
                 │
                 ▼
          Terraform creates
                 │
          ┌──────┴──────┐
          ▼             ▼
      Subnet[0]      Subnet[1]

for_each

Use for_each when resources have meaningful unique names/keys.

Example:

variable "buckets" {
  default = [
    "uploads",
    "backups",
    "logs"
  ]
}

Convert the list to a set:

resource "aws_s3_bucket" "bucket" {
  for_each = toset(var.buckets)

  bucket = "taskify-${each.value}"
}

Terraform creates resources identified by their values:

aws_s3_bucket.bucket["uploads"]
aws_s3_bucket.bucket["backups"]
aws_s3_bucket.bucket["logs"]

5. each.key and each.value

When using for_each, Terraform provides:

each.key
each.value

This becomes especially useful with a map.

variable "servers" {
  default = {
    frontend = "t3.micro"
    backend  = "t3.small"
  }
}

Use:

resource "aws_instance" "server" {
  for_each = var.servers

  ami           = "ami-123456"
  instance_type = each.value

  tags = {
    Name = each.key
  }
}

Here:

servers
│
├── frontend = t3.micro
│      │           │
│      │           └── each.value
│      └────────────── each.key
│
└── backend = t3.small
       │          │
       │          └── each.value
       └───────────── each.key

Terraform creates:

aws_instance.server["frontend"]
    instance_type = "t3.micro"

aws_instance.server["backend"]
    instance_type = "t3.small"