Skip to content

Meta-Arguments in Terraform

Meta-arguments are special arguments that can be used with any resource type.


1. count

Purpose: Create multiple instances of a resource.

Basic Example

resource "aws_instance" "web" {
  count         = 3
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

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

# Creates:
# - web-server-0
# - web-server-1
# - web-server-2

Conditional Creation

variable "create_instance" {
  type    = bool
  default = true
}

resource "aws_instance" "web" {
  count = var.create_instance ? 1 : 0

  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}

Referencing count Resources

# Reference all instances
output "all_ips" {
  value = aws_instance.web[*].public_ip
}

# Reference specific instance
output "first_ip" {
  value = aws_instance.web[0].public_ip
}

2. for_each

Purpose: Create multiple instances using a map or set.

With Set

variable "users" {
  type = set(string)
  default = ["alice", "bob", "charlie"]
}

resource "aws_iam_user" "users" {
  for_each = var.users
  name     = each.key

  tags = {
    User = each.value
  }
}

With Map

variable "instances" {
  type = map(object({
    instance_type = string
    ami           = string
  }))

  default = {
    web = {
      instance_type = "t2.micro"
      ami           = "ami-abc123"
    }
    db = {
      instance_type = "t2.small"
      ami           = "ami-def456"
    }
  }
}

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

  instance_type = each.value.instance_type
  ami           = each.value.ami

  tags = {
    Name = each.key
  }
}

count vs for_each

┌──────────────────────────────────────────────────────────┐
│  count vs for_each                                       │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  count:                                                  │
│  ✅ Simple numeric iteration                            │
│  ✅ Conditional creation (count = condition ? 1 : 0)    │
│  ❌ Fragile when removing items from middle             │
│  ❌ Uses numeric index                                  │
│                                                          │
│  for_each:                                               │
│  ✅ Stable keys (no reordering issues)                  │
│  ✅ Works with maps and sets                            │
│  ✅ Better for dynamic lists                            │
│  ❌ Slightly more complex syntax                        │
│                                                          │
│  Recommendation: Use for_each for most cases            │
└──────────────────────────────────────────────────────────┘

3. depends_on

Purpose: Explicit dependency when implicit dependencies don't work.

resource "aws_iam_role" "example" {
  name = "example-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Principal = {
        Service = "ec2.amazonaws.com"
      }
    }]
  })
}

resource "aws_iam_role_policy" "example" {
  name = "example-policy"
  role = aws_iam_role.example.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action   = ["s3:*"]
      Effect   = "Allow"
      Resource = "*"
    }]
  })
}

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  # Explicit dependency
  depends_on = [
    aws_iam_role_policy.example
  ]
}

When to use: - Hidden dependencies (e.g., IAM eventual consistency) - Dependencies on modules - Dependencies that Terraform can't detect automatically


4. provider

Purpose: Use alternate provider configuration.

# Default provider
provider "aws" {
  region = "us-east-1"
}

# Alternate provider with alias
provider "aws" {
  alias  = "west"
  region = "us-west-2"
}

# Use default provider
resource "aws_instance" "east" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}

# Use alternate provider
resource "aws_instance" "west" {
  provider = aws.west

  ami           = "ami-0d1cd67c26f5fca19"
  instance_type = "t2.micro"
}