TFLAB10-count: Creating Multiple Resources from One Block

count: Creating Multiple Resources from One Block

🔧 Terraform Core ⭐ Beginner count count.index Conditional Creation splat [*]

Scenario

Your team needs three identical S3 buckets for different data partitions — but you don't want to write three separate resource blocks. That's copy-paste code, and it doesn't scale when you need ten buckets next month.

You also need a bucket that only exists in production — in dev, it shouldn't be created at all. The count meta-argument solves both problems: creating multiple instances and conditionally creating resources.

Your Objectives
  • Use count to create 3 S3 buckets from one resource block.
  • Use count.index to give each bucket a unique name.
  • Use the [*] splat expression to output all bucket names.
  • Use count = var.create ? 1 : 0 to conditionally create a resource.
  • Reference a counted resource by index: aws_s3_bucket.data[0].

Additional Context

count creates multiple instances of a resource. Each instance is tracked by its index: aws_s3_bucket.data[0], aws_s3_bucket.data[1], etc. If you later change the count or reorder a list, Terraform may destroy and recreate resources because the index shifted. This is the main drawback of count — for maps or sets where order doesn't matter, use for_each instead (covered in the next lab).

variables.tf

variable "bucket_count" {
  description = "Number of data partition buckets to create."
  type        = number
  default     = 3
}

variable "create_archive_bucket" {
  description = "Whether to create the archive bucket (prod-only)."
  type        = bool
  default     = false
}

variable "aws_region" { type = string; default = "us-east-1" }

main.tf

# main.tf

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
}

provider "aws" { region = var.aws_region }

data "aws_caller_identity" "current" {}

# ─── CREATE MULTIPLE RESOURCES WITH count ───
resource "aws_s3_bucket" "data_partition" {
  count = var.bucket_count    # Creates N instances

  # count.index is 0, 1, 2, ... (N-1)
  bucket = "data-partition-${count.index}-${data.aws_caller_identity.current.account_id}"

  tags = {
    Name        = "data-partition-${count.index}"
    Partition   = tostring(count.index)
    ManagedBy   = "terraform"
  }
}

# ─── CONDITIONAL CREATION WITH count ───
# count = 1 creates the resource; count = 0 skips it entirely
resource "aws_s3_bucket" "archive" {
  count = var.create_archive_bucket ? 1 : 0

  bucket = "archive-${data.aws_caller_identity.current.account_id}"
  tags   = { Name = "archive-bucket", ManagedBy = "terraform" }
}

outputs.tf

# [*] splat expression — collects one attribute from ALL instances
output "all_bucket_names" {
  description = "Names of all data partition buckets."
  value       = aws_s3_bucket.data_partition[*].id
}

output "all_bucket_arns" {
  value = aws_s3_bucket.data_partition[*].arn
}

# Reference a specific instance by index
output "first_bucket" {
  value = aws_s3_bucket.data_partition[0].id
}

# Conditional output — only output if the archive bucket was created
output "archive_bucket" {
  value = var.create_archive_bucket ? aws_s3_bucket.archive[0].id : "not created"
}

Workflow Commands

terraform init
terraform apply   # creates 3 buckets, skips archive

# Create 5 buckets instead
terraform apply -var="bucket_count=5"

# Enable archive bucket (conditional creation)
terraform apply -var="create_archive_bucket=true"

# Reduce count — Terraform DESTROYS the removed instances
terraform apply -var="bucket_count=2"

terraform destroy
✓ Expected Output After Apply (3 buckets)
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

all_bucket_arns  = [
  "arn:aws:s3:::data-partition-0-123456789012",
  "arn:aws:s3:::data-partition-1-123456789012",
  "arn:aws:s3:::data-partition-2-123456789012",
]
all_bucket_names = [
  "data-partition-0-123456789012",
  "data-partition-1-123456789012",
  "data-partition-2-123456789012",
]
archive_bucket   = "not created"
first_bucket     = "data-partition-0-123456789012"