DEV Community

Cover image for AWS Terraform Meta Arguments | Count, depends_on, for_each
Adarsh Gupta
Adarsh Gupta

Posted on

AWS Terraform Meta Arguments | Count, depends_on, for_each

Terraform becomes truly powerful when you start using meta-arguments — special parameters that change how resources are created, managed, and related to each other. While Terraform syntax is easy to learn, mastering meta-arguments like count, for_each, and depends_on is what enables you to build dynamic, scalable, and production-ready AWS infrastructure.

This guide explains each meta-argument in detail with clear examples, best practices, and common real-world scenarios where these features become essential.


Understanding Meta Arguments in Terraform

Meta-arguments are not specific to any resource type. Instead, they can be applied to any Terraform resource, module, or data source to control creation patterns and dependency behavior.

The three foundational meta-arguments are:

  • count → create multiple instances of a resource using index numbers
  • for_each → create multiple resources using map or set keys (more predictable)
  • depends_on → explicitly define resource ordering and dependencies

Let’s explore each one in detail.


1. count — Create Resources Dynamically Using Indexing

count is the simplest way to create multiple instances of the same resource. It works by creating resources based on a number, and you use count.index to reference each instance.

Example — Creating Multiple S3 Buckets Using count

variable "bucket_names" {
  type    = list(string)
  default = ["app-logs", "media-storage", "archive-backups"]
}

resource "aws_s3_bucket" "buckets" {
  count  = length(var.bucket_names)
  bucket = var.bucket_names[count.index]
}
Enter fullscreen mode Exit fullscreen mode

Terraform will create three buckets and name them based on list values. This is the simplest way to scale resource creation.

When to Use count

  • When resources are identical
  • When order doesn’t matter
  • When your inputs are lists, not maps
  • When index-based naming is acceptable

Limitations

The main drawback of count is index shifting.
If the order of your list changes, Terraform may destroy and recreate resources unnecessarily. For example, adding a new item in the middle of the list changes all subsequent indexes.


2. for_each — Create Resources with Stable Keys

for_each solves the indexing problem by using keys instead of positions. This ensures resources remain stable even when items are added or removed.

Example — Creating Buckets Using for_each

variable "buckets" {
  type = map(string)
  default = {
    logs   = "app-logs"
    media  = "media-storage"
    backup = "archive-backups"
  }
}

resource "aws_s3_bucket" "bucket" {
  for_each = var.buckets
  bucket   = each.value
}
Enter fullscreen mode Exit fullscreen mode

Here, resources are created using keys (logs, media, backup) instead of index numbers.

When to Use for_each

  • When you want stable instances
  • When input is a set or map
  • When you need meaningful Terraform addresses like:
aws_s3_bucket.bucket["logs"]
Enter fullscreen mode Exit fullscreen mode

Why for_each Is Better Than count

Unlike count, adding a new key does not recreate other resources. Keys remain stable indefinitely, making this the preferred method for production infrastructure.


3. depends_on — Explicitly Define Resource Dependencies

Terraform generally detects dependencies automatically. For example, if an EC2 instance references a subnet ID, Terraform understands the subnet must be created first.

However, sometimes you must explicitly declare dependencies — especially when:

  • Provisioners are involved
  • Resources don’t reference each other directly
  • Modules need ordering
  • Upstream actions must complete first

Example — Wait for S3 Bucket Before Running Local Script

resource "aws_s3_bucket" "example" {
  bucket = "demo-meta-argument-bucket"
}

resource "null_resource" "notify" {
  depends_on = [aws_s3_bucket.example]

  provisioner "local-exec" {
    command = "echo S3 bucket created!"
  }
}
Enter fullscreen mode Exit fullscreen mode

When to Use depends_on

  • When implicit dependency cannot be detected
  • When actions must occur in strict sequence
  • When you must enforce ordering between modules

Best Practice

Use depends_on only when needed.
Terraform is good at understanding dependencies automatically, so avoid overusing it to prevent unnecessary serialization of your plan.


Putting It All Together — Real-World Example

Here’s a scenario combining all three meta-arguments:

variable "apps" {
  type = map(string)
  default = {
    app1 = "app1-logs"
    app2 = "app2-logs"
  }
}

resource "aws_s3_bucket" "buckets" {
  for_each = var.apps
  bucket   = each.value
}

resource "null_resource" "verify" {
  count      = length(var.apps)
  depends_on = [aws_s3_bucket.buckets]

  provisioner "local-exec" {
    command = "echo Created bucket ${count.index}"
  }
}
Enter fullscreen mode Exit fullscreen mode

In this setup:

  • for_each ensures stable bucket creation
  • count runs verification for each bucket
  • depends_on ensures verification runs after bucket creation

This pattern appears frequently in CI/CD pipelines, multi-environment deployments, and state validation workflows.


Conclusion

Meta-arguments like count, for_each, and depends_on are the backbone of dynamic Terraform configurations. They help you scale your AWS infrastructure safely, maintain predictable behavior, and enforce dependency flow.

If you want to grow as a Terraform engineer, understanding these concepts is essential. Use count for simple repetition, for_each for stable and meaningful keys, and depends_on when Terraform needs guidance on ordering.


Reference Video

@piyushsachdeva

Top comments (0)