count
Explained with Practical ExamplesTerraform is a powerful Infrastructure as Code (IaC) tool that allows you to define and provision infrastructure resources using configuration files.
In this article we will review Terraform's ability to dynamically create multiple instances of a resource
using the count
meta-argument.
We'll begin with a simple example, such as creating multiple similar Google Cloud Storage (GCS) buckets, and progress
to more complex scenarios, including dynamically creating resources from input objects. By the end of this
tutorial, you'll understand not just how count
works, but when and why to use it to simplify and scale
your configurations.
To follow along you need a basic understanding of Terraform syntax and have the following set up:
gcloud auth application-default login
, or
Once you have the tools above ready, you're all set to explore how count
can improve your Terraform
configurations!
count
Terraform's count
meta-argument is one of the simplest yet highly effective tools in your IaC toolkit.
It lets you specify (without duplicating the resource code blocks) how many copies of a given resource or
module Terraform should create.
Basic count
syntax:
If count
is present in a resource block and greater than 0, Terraform will create the specified number
of instances of that resource.
The result is a list of resources referenced by the name RESOURCE_TYPE.NAME
, not individual named resources.
You can access individual objects in the list by providing the index value - RESOURCE_TYPE.NAME[index]
.
Note: Terraform uses zero-based indexing, so the first instance is always RESOURCE_TYPE.NAME[0]
.
For example, if count = 3
, Terraform will create three instances of the resource:
RESOURCE_TYPE.NAME[0]
, RESOURCE_TYPE.NAME[1]
, and RESOURCE_TYPE.NAME[2]
.
When you set count = 1
, Terraform will create exactly one instance - RESOURCE_TYPE.NAME[0]
.
If count = 0
, Terraform will not create any instances. Terraform ignores any resource
block with count = 0
when planning/applying, as if the resource block doesn't exist at all. If a resource
was previously created with count = 1
(or more), and then you change the configuration to count = 0
,
Terraform will destroy all existing resource instances.
Referencing Individual Instances with count.index
:
When you use count
, Terraform gives you access to a special variable called count.index
.
This represents the index (starting from 0) of the current resource instance being created. count.index
is commonly used to define individual resource names, labels, or configuration settings.
Why Use count
?
The main advantages of using count
include:
count
to define it once and create multiple instances.count = 1
or count = 0
to enable or disable a resource
based on a variable.
Let's start with a simple example that demonstrates how to use the count
meta-argument to create
multiple Google Cloud Storage buckets.
Goal: We'll create three Cloud Storage buckets, each with a unique name, using a single resource block
with the count
meta-argument.
Terraform Code:
How It Works:
var.project_id
- this variable should be set to your actual GCP project ID. You can define it
directly in the file or pass it as a CLI parameter.count = 3
tells Terraform to create three buckets.${count.index}
- this is the index number (0 to 2) for each bucket. We use it to make each bucket
name unique.force_destroy = true
allows you to delete a bucket that contains objects (to simplify
cleanup process).for
expression iterates over the resource list google_storage_bucket.example
to retrieve bucket names.Important: Bucket names must be globally unique across all of Google Cloud. Including the project ID and an index helps avoid naming conflicts.
How to Apply This Configuration:
main.tf
export TF_VAR_project_id=YOUR_PROJECT_ID
terraform init
terraform apply
Terraform will create three buckets with the following names:
tf-demo-bucket-YOUR_PROJECT_ID-0
tf-demo-bucket-YOUR_PROJECT_ID-1
tf-demo-bucket-YOUR_PROJECT_ID-2
Individual buckets can be referenced by using the indexes of the google_storage_bucket.example
list.
For example, to get bucket names use:
google_storage_bucket.example[0].name
google_storage_bucket.example[1].name
google_storage_bucket.example[2].name
Cleaning Up:
To delete the buckets, simply run terraform destroy
. Confirm when prompted, and Terraform will delete
all the created resources.
Summary:
In this example, we illustrated how to:
count
to create multiple resourcescount.index
RESOURCE_TYPE.NAME[index]
for
In some cases resources need to be created only under certain conditions.
We can utilize count
meta-argument to implement such if-then
logic in Terraform code.
Goal: Let's say we want to create a Cloud Storage bucket only if the var.create_bucket
variable is true.
Terraform Code:
How It Works:
count = (var.enable_bucket ? 1 : 0)
- this is the key line. It evaluates the boolean variable
var.enable_bucket
:
true
, it sets count
to 1 and google_storage_bucket.optional[0]
is created.false
, count
is 0 and no resource is created.output
block also checks the condition (var.create_bucket ?
) to avoid referencing
a non-existent resource and prevent runtime errors.force_destroy = true
allows you to delete a bucket that contains objects (to simplify cleanup).How to Apply This Configuration:
main.tf
create_bucket
variable to true
or false
as desired export TF_VAR_project_id=YOUR_PROJECT_ID
terraform init
terraform apply
If enable_bucket
is true, the bucket will be created. You'll see the bucket name in the output only if it exists.
If enable_bucket
is false, nothing is created, and no error occurs.
If a resource was previously created with count = 1
, and then you change the configuration to set
count = 0
, Terraform will:
Cleaning Up:
To delete the buckets, simply run terraform destroy
. Confirm when prompted, and Terraform will delete
all the created resources.
Summary:
Using count
for conditional resource creation is:
In many Terraform projects, you'll want to create multiple resources with specific parameters based on input values,
such as a list of names, locations, etc. Terraform's count
meta-argument, combined with list input variables, enables
this dynamic behavior.
Goal: We want to create multiple Google Cloud Storage buckets, each with a custom name from a list defined in an input variable.
Terraform Code:
How It Works:
count = length(var.bucket_names)
determines how many buckets to create based on the number of names
provided in the bucket_names
list.var.bucket_names[count.index]
retrieves the name for each resource being created.${...}-${var.project_id}
appends the project ID to ensure globally unique bucket names.force_destroy = true
allows you to delete a bucket that contains objects (to simplify
cleanup process).output
uses a for
expression to iterate over the list of created buckets
google_storage_bucket.multi
and return bucket URLs.How to Apply This Configuration:
main.tf
export TF_VAR_project_id=YOUR_PROJECT_ID
terraform init
terraform apply
After applying, you'll see the list of bucket URLs in the output, e.g.:
To access individual bucket attributes in expressions or outputs, use index-based reference, for example:
google_storage_bucket.multi[0].name
google_storage_bucket.multi[1].location
Apply this approach only when you're confident about the list size and order.
To illustrate how changes to the input list may affect the existing objects, let's remove the "backup"
name from the bucket_names
list and re-run terraform apply
.
Since there are now only two names on the list - ["logs", "assets"]
, Terraform detects the changes in
the configuration and performs the following actions:
As you can se from the output, Terraform destroyed two buckets - backups-YOUR_PROJECT_ID
and
assets-YOUR_PROJECT_ID
and then re-created the "assets"
bucket.
Cleaning Up:
To delete the buckets, simply run terraform destroy
. Confirm when prompted, and Terraform will delete
all the created resources.
Summary:
In this example, we illustrated:
count
meta-argument together with a list input variable to dynamically create
resources with custom attribute valuescount.index
) maps input values to each resource
While this approach provides a simple and convenient way of creating multiple resources, it may produce unexpected
results when you modify the values or the number of items on the list. Always review the terraform plan
output to make sure the results match your expectations.
count
with Complex Object Input
In a situation when you need to create multiple similar objects and supply more than one input value per resource -
such as name, location, or labels, you can combine count
meta-argument with an object type input variable.
In this example we'll use a list of maps as an input variable to drive such creation.
Goal: We need to create several Google Cloud Storage buckets, each with different:
Terraform Code:
How It Works:
var.buckets
contains a list of objects (maps), each defining individual bucket properties.count = length(var.buckets)
determines how many buckets to create based on the number of objects
in var.buckets
.var.buckets[count.index]
selects the corresponding parameter object for each resource instance.force_destroy = true
allows you to delete a bucket that contains objects (to simplify
cleanup process).output
block returns configuration details for created buckets.How to Apply This Configuration:
main.tf
export TF_VAR_project_id=YOUR_PROJECT_ID
terraform init
terraform apply
After applying, Terraform creates 3 GCS buckets, each with unique settings:
You can access a specific resource from the list by using index: google_storage_bucket.multi[0].url
, or
by filtering output dynamically:
Cleaning Up:
To delete the buckets, simply run terraform destroy
. Confirm when prompted, and Terraform will delete
all the created resources.
Summary:
var.<variable>[count.index].<attribute>
.
While count
meta-argument is a powerful tool in Terraform, it comes with certain limitations and
behavioral caveats that can lead to unexpected results if not properly understood. Here are key points to be
aware of when using count
.
Index-Based Access
When using count
, resources are created as a list, and each instance is accessed using an index
(resource_name[0]
, resource_name[1]
, etc.).
Changes in Count Value Can Trigger Resource Recreation
Altering the value of count
or changing the length of the input list may destroy one or more instances.
This can cause side effects such as:
Conditional Logic Requires Careful Output Handling
Referencing resource_name[0]
when count = 0
(no resources were created) will result in a
Terraform error. Use conditional expressions to avoid referencing a resource that doesn't exist.
Use count
for simple repetition when:
Utilize count
with conditional expressions for optional resources:
count = condition ? 1 : 0
and combine with conditional outputs to safely handle
optional resourceAvoid hard-coding indices
resource_name[1]
) unless the position
in the list is guaranteed to remain constant. Use looping expressions like for
or dynamic outputs instead.
Prefer for_each
for complex or named resources when
Terraform's count
meta-argument enables you to efficiently create and manage
multiple instances of a resource using simple logic or dynamic input. From basic repetition to conditional and
data-driven infrastructure, count
helps reduce code duplication and streamline your configurations.
While it's a great tool for many scenarios, it's important to understand its limitations and apply best practice, especially when handling optional resources or dynamic lists.
With thoughtful use, count
can significantly enhance the flexibility and scalability of your Terraform
projects.
Understanding the nuances of count
is key to writing safe, scalable Terraform code. When used
appropriately, it enables powerful resource automation. When misused, it can lead to fragile infrastructure and
hard-to-diagnose issues.
See Also:
Handling Terraform State in Multi-Environment Deployments
Understanding Terraform Variable Precedence
Terraform Value Types Tutorial
Terraform for_each
Tutorial with Practical Examples
Exploring Terraform dynamic
Blocks with GCP Examples
Working with External Data in Terraform
Handling Sensitive and Ephemeral Data in Terraform
Terraform Modules FAQ