Terraform State: Creating Multiple Resources with Count
Scenario
Your data engineering team is running an experiment and needs 3 identical Cloud Storage buckets, one for each phase of their pipeline (ingest, process, serve). Writing three separate google_storage_bucket blocks is repetitive and hard to maintain. You will use the count meta-argument to iterate and create them dynamically.
- Define a variable representing the number of buckets requested (default to 3).
- Use the count meta-argument within a google_storage_bucket.
- Use count.index to give each bucket a distinct, incremented name (e.g., data-bucket-0).
- Use the splat operator ([*]) to output an array of all generated bucket names.
Additional Context
The catch with count: Terraform tracks resources created with `count` via their index number in an array (e.g., `google_storage_bucket.data[0]`, `[1]`, `[2]`). If you later decide to decrease the count to 2, Terraform destroys the highest index (`[2]`). This behavior makes `count` dangerous if order matters or if the user intends to remove an item from the middle of the list.
For resources where identity matters (like specific IAM service accounts or named networks), `for_each` is vastly superior. `count` should only be used where the instances are completely identical and interchangeable (like spinning up 5 worker VMs).
variables.tf
variable "project_id" { type = string }
variable "gcp_region" { type = string; default = "us-central1" }
variable "bucket_count" {
type = number
default = 3
description = "Number of identical storage buckets to create"
}main.tf
provider "google" {
project = var.project_id
region = var.gcp_region
}
# Need a random suffix to ensure globally unique names across all buckets
resource "random_id" "suffix" { byte_length = 4 }
# The count meta-argument creates multiple copies of this resource
resource "google_storage_bucket" "data_layers" {
count = var.bucket_count
# count.index gives the current iteration number (0, 1, 2...)
name = "pipeline-layer-${count.index}-${random_id.suffix.hex}"
location = var.gcp_region
force_destroy = true
labels = {
pipeline_stage = "layer_${count.index}"
managed_by = "terraform_count"
}
}outputs.tf
# The '*' (splat) operator collects attributes across all instances created by count
output "all_bucket_names" {
value = google_storage_bucket.data_layers[*].name
}
# You can still reference specific indexes directly
output "first_bucket_url" {
value = google_storage_bucket.data_layers[0].url
}Workflow Commands
terraform init
terraform apply -var="project_id=my-gcp-project-123"
# See what happens when you decrease the count:
terraform plan -var="project_id=my-gcp-project-123" -var="bucket_count=2"
# Terraform will plan to destroy ONLY index 2.
terraform destroy -var="project_id=my-gcp-project-123"Apply complete! Resources: 4 added, 0 changed, 0 destroyed. Outputs: all_bucket_names = [ "pipeline-layer-0-a1b2c3d4", "pipeline-layer-1-a1b2c3d4", "pipeline-layer-2-a1b2c3d4", ] first_bucket_url = "gs://pipeline-layer-0-a1b2c3d4"

