Devops

Terraform Count Explained: Create Multiple Resources the Smart Way

April 7, 2026
Published
#Automation#Cloud#DevOps#Infrastructure as Code#Terraform

If you've ever found yourself copying and pasting the same Terraform resource block just to create slight variations, you're doing more work than necessary. Terraform's count meta-argument exists exactly for this scenario.

Instead of duplicating code, you can declaratively define how many instances of a resource you want—and let Terraform handle the rest.

What is Terraform Count?

count is a meta-argument that allows you to create multiple instances of a resource (or module) using a single block of configuration.

At its simplest, it looks like this:

TEXT
1resource "aws_instance" "web" {
2  count = 3
3
4  ami           = "ami-123456"
5  instance_type = "t3.micro"
6}

This will create three EC2 instances:

  • aws_instance.web[0]
  • aws_instance.web[1]
  • aws_instance.web[2]

Each instance is indexed numerically, starting from 0.

Using count.index for Customization

Here's where things get interesting. Terraform gives you access to count.index, which represents the current instance number.

You can use it to customize each resource:

TEXT
1resource "aws_instance" "web" {
2  count = 3
3
4  ami           = "ami-123456"
5  instance_type = "t3.micro"
6
7  tags = {
8    Name = "web-${count.index}"
9  }
10}

This produces instances named:

  • web-0
  • web-1
  • web-2

It’s simple but surprisingly powerful.

Driving Count with Variables

Hardcoding numbers isn’t very flexible. A common pattern is to control count through variables:

TEXT
1variable "instance_count" {
2  type    = number
3  default = 2
4}
5
6resource "aws_instance" "web" {
7  count = var.instance_count
8
9  ami           = "ami-123456"
10  instance_type = "t3.micro"
11}

This makes your infrastructure adaptable across environments. For example:

  • Dev → 1 instance
  • Staging → 2 instances
  • Production → 5 instances

Conditional Resource Creation with Count

A neat trick developers often use is leveraging count for conditional logic.

JSON
1resource "aws_s3_bucket" "logs" {
2  count = var.enable_logs ? 1 : 0
3
4  bucket = "my-app-logs"
5}

If enable_logs is false, Terraform simply doesn't create the resource.

This avoids messy conditional blocks and keeps configurations clean.

Referencing Resources Created with Count

When you use count, you must reference resources using index notation.

TEXT
1output "instance_ids" {
2  value = aws_instance.web[*].id
3}

The [*] syntax collects values from all instances.

To access a specific instance:

TEXT
1aws_instance.web[0].id

Where Count Starts to Break Down

Count is great—until your resources stop being identical.

Consider this scenario:

TEXT
1variable "instance_names" {
2  default = ["api", "worker", "frontend"]
3}
4
5resource "aws_instance" "web" {
6  count = length(var.instance_names)
7
8  tags = {
9    Name = var.instance_names[count.index]
10  }
11}

This works fine initially. But what happens if you remove "worker" from the list?

Terraform will shift indexes and potentially destroy and recreate resources unexpectedly.

This is one of the biggest pitfalls of Terraform count: it is index-based, not identity-based.

Count vs for_each (Quick Reality Check)

A common mistake developers make is overusing count when for_each is a better fit.

Use count when:

  • Resources are nearly identical
  • You only need a number (e.g., 3 instances)

Use for_each when:

  • Each resource has a unique identity
  • You are working with maps or sets
  • You want stable resource tracking

If you’re dealing with named resources or frequently changing lists, for_each will save you from painful state issues.

Practical Example: Multi-AZ Deployment

Let’s put everything together with a realistic scenario:

TEXT
1variable "availability_zones" {
2  default = ["us-east-1a", "us-east-1b", "us-east-1c"]
3}
4
5resource "aws_instance" "web" {
6  count = length(var.availability_zones)
7
8  ami           = "ami-123456"
9  instance_type = "t3.micro"
10  availability_zone = var.availability_zones[count.index]
11
12  tags = {
13    Name = "web-${var.availability_zones[count.index]}"
14  }
15}

This distributes instances across availability zones without repeating configuration.

Performance and State Considerations

Using count doesn’t just affect readability—it impacts Terraform state behavior:

  • Index shifts can trigger resource recreation
  • Large counts can slow down plan/apply operations
  • Debugging becomes harder with numeric indexing

For small, predictable sets, count is efficient and clean. For dynamic infrastructure, it can become fragile.

Common Mistakes to Avoid

  • Relying on list order that might change later
  • Mixing count with complex conditional logic
  • Using count where for_each provides better stability
  • Forgetting to update references when switching from single to multiple resources

When Count Really Shines

Despite its limitations, count is perfect for:

  • Stateless compute instances
  • Auto-scaled baseline infrastructure
  • Temporary or disposable environments
  • Feature toggles (enable/disable resources)

In these cases, its simplicity is actually a strength.

Wrapping It Up

Terraform count is one of those features that feels trivial at first—but becomes incredibly useful once you start scaling infrastructure.

Use it when you need repetition without complexity. But be cautious when your infrastructure starts requiring identity and stability.

If you're ever unsure whether to use count or something more advanced, it's usually a sign to pause and evaluate how your resources evolve over time.

Comments

Leave a comment on this article with your name, email, and message.

Loading comments...

Similar Articles

More posts from the same category you may want to read next.

Share: