All Products
Search
Document Center

Terraform:count

Last Updated:Apr 10, 2025

Overview

By default, one resource block can be used to configure one real infrastructure object. Similarly, one module block includes the content of the child module blocks in the configurations. If you want to manage multiple similar objects, such as a fixed pool of compute instances without writing a block for each object, you can use the Terraform count or for_each argument.

count is a meta-argument in Terraform. It allows you to declare multiple instances in a resource or module. If the resource or module contains the count argument that carries an integer value, Terraform creates that number of instances. count is used to create resource replicas based on a specified value. Each replica is an independent infrastructure object. Using count is the simplest way to create multiple resources at the same time. count is particularly ideal for resource sets that use a similar structure, such as server clusters, similar buckets, and network components.

This topic describes the syntax of the count meta-argument and how to use it. This topic also provides examples on how to use count in Alibaba Cloud environments to simplify infrastructure management.

Note that the same resource or module block cannot use count and for_each at the same time.

Syntax

count is a meta-argument defined by Terraform. count can be used together with modules and all resource types.

The value of count must be an integer. The number of resources or module instances to be created is determined by the value of argument. Each instance is associated with a unique infrastructure object. When you configure applications, each object is independently created, updated, and destroyed.

Usage

resource "alicloud_instance" "server" {
  count = 4 # Create four similar ECS instances.

  instance_name   = "server-${count.index}"
  instance_type   = "ecs.s6-c1m2.small"
  image_id        = "aliyun_2_1903_x64_20G_alibase_20230523.vhd"
  vswitch_id      = "vsw-abc123456"
  security_groups = ["sg-abc123456"]

  tags = {
    Name = "Server ${count.index}"
  }
}

count object

In a block that contains the count argument, the expression can use an additional count object. This allows you to modify the configurations of each instance. This object has the following attribute:

  • count.index: The index number of the instance. Index numbers start from 0.

Use expressions in the count argument

The count meta-argument supports numeric expressions. However, the value of count must be known before Terraform performs any remote resource operations. Therefore, count cannot reference unknown resource attributes before it is applied. For example, the unique ID generated by a remote API operation during object creation cannot be referenced by count.

Reference instances

After you configure the count argument, Terraform distinguishes between the block and the resources or module instances that are associated with the block. Instances are identified by indexes, which start from 0.

  • Use <TYPE>.<NAME> or module.<NAME> to reference a resource block. Example: alicloud_instance.server.

  • Use <TYPE>.<NAME>[<INDEX>] or module.<NAME>[<INDEX>] to reference a single instance. Examples: alicloud_instance.server[0] and alicloud_instance.server[1].

If a resource or module does not contain the count or for_each argument, the resource or module can be referenced without an index or key.

When the resources in the child modules from multiple instances plan to output and display other UI elements, the resources are prefixed with module.<NAME>[<KEY>]. If a module does not contain the count or for_each argument, the address does not contain the module index because the module can be referenced by name.

Note that in a nested provisioner or connection block, the current resource instance is referenced by a special self object, instead of the entire resource block.

Examples

Create multiple ECS instances

resource "alicloud_instance" "web_servers" {
  count = 3

  instance_name   = "web-server-${count.index + 1}"
  instance_type   = "ecs.s6-c1m2.small"
  image_id        = "aliyun_2_1903_x64_20G_alibase_20230523.vhd"
  vswitch_id      = "vsw-abc123456"
  security_groups = ["sg-abc123456"]

  system_disk_category = "cloud_efficiency"
  system_disk_size     = 40

  tags = {
    Name  = "WebServer-${count.index + 1}"
    Role  = "web"
    Stage = "production"
  }
}

Create multiple OSS buckets

variable "bucket_names" {
  description = "List of bucket name prefixes"
  type        = list(string)
  default     = ["logs", "backups", "configs"]
}

resource "alicloud_oss_bucket" "buckets" {
  count = length(var.bucket_names)

  bucket = "${var.bucket_names[count.index]}-${random_id.suffix.hex}"
  acl    = "private"

  tags = {
    Name        = var.bucket_names[count.index]
    Environment = "Production"
  }
}

resource "random_id" "suffix" {
  byte_length = 4
}

Create resources based on conditions

You can use count to create resources based on conditions:

variable "create_slb" {
  description = "Whether to create SLB"
  type        = bool
  default     = true
}

resource "alicloud_slb_load_balancer" "app" {
  # Create the resource only when create_slb is set to true.
  count = var.create_slb ?  1 : 0

  load_balancer_name = "app-lb"
  address_type       = "internet"
  load_balancer_spec = "slb.s2.small"
  
  tags = {
    Name = "ApplicationLB"
  }
}

Use count in a module

variable "enable_high_availability" {
  description = "Whether to deploy in high availability mode with multiple zones"
  type        = bool
  default     = false
}

module "primary_zone" {
  source = "./modules/zone_deployment"
  
  zone_id = "cn-hangzhou-h"
  # Other configurations.
}

module "secondary_zone" {
  source = "./modules/zone_deployment"
  
  # The resource is deployed in the second zone only when high availability is enabled.
  count   = var.enable_high_availability ?  1 : 0
  zone_id = "cn-hangzhou-i"
  # Other configurations.
}

How to choose between count and for_each

count is more applicable if the instances are nearly identical. If some of their arguments require different values that cannot be derived directly from integers, for_each provides higher security.

Before for_each is available, the common method is to derive count from the length of the list and use count.index to query the original list value. Sample code:

variable "vswitch_ids" {
  type = list(string)
}

resource "alicloud_instance" "server" {
  # Create an instance for each vSwitch.
  count = length(var.vswitch_ids)

  instance_name   = "server-${count.index + 1}"
  instance_type   = "ecs.s6-c1m2.small"
  image_id        = "aliyun_2_1903_x64_20G_alibase_20230523.vhd"
  vswitch_id      = var.vswitch_ids[count.index]

  tags = {
    Name = "Server ${count.index + 1}"
  }
}

This method is inefficient because the resource instances are identified by their indexes instead of the string values in the list. If you delete an element from the list, each instance after the deleted element can detect the change in the vswitch_id value. The number of remote objects that need to be changed is higher than expected. for_each supports flexible configurations without making unexpected changes.

This topic is developed based on the Terraform document The count Meta-Argument. You can read the Terraform document for more details.