count: Creating Multiple Resources from One Block
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.
- 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 destroyApply 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"

