--- layout: "language" page_title: "The count Meta-Argument - Configuration Language" --- # The `count` Meta-Argument -> **Version note:** Module support for `count` was added in Terraform 0.13, and previous versions can only use it with resources. -> **Note:** A given resource or module block cannot use both `count` and `for_each`. > **Hands-on:** Try the [Manage Similar Resources With Count](https://learn.hashicorp.com/tutorials/terraform/count?in=terraform/0-13&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial on HashiCorp Learn. By default, a [resource block](/docs/language/resources/syntax.html) configures one real infrastructure object. (Similarly, a [module block](/docs/language/modules/syntax.html) includes a child module's contents into the configuration one time.) However, sometimes you want to manage several similar objects (like a fixed pool of compute instances) without writing a separate block for each one. Terraform has two ways to do this: `count` and [`for_each`](/docs/language/meta-arguments/for_each.html). If a resource or module block includes a `count` argument whose value is a whole number, Terraform will create that many instances. ## Basic Syntax `count` is a meta-argument defined by the Terraform language. It can be used with modules and with every resource type. The `count` meta-argument accepts a whole number, and creates that many instances of the resource or module. Each instance has a distinct infrastructure object associated with it, and each is separately created, updated, or destroyed when the configuration is applied. ```hcl resource "aws_instance" "server" { count = 4 # create four similar EC2 instances ami = "ami-a1b2c3d4" instance_type = "t2.micro" tags = { Name = "Server ${count.index}" } } ``` ## The `count` Object In blocks where `count` is set, an additional `count` object is available in expressions, so you can modify the configuration of each instance. This object has one attribute: - `count.index` — The distinct index number (starting with `0`) corresponding to this instance. ## Using Expressions in `count` The `count` meta-argument accepts numeric [expressions](/docs/language/expressions/index.html). However, unlike most arguments, the `count` value must be known _before_ Terraform performs any remote resource actions. This means `count` can't refer to any resource attributes that aren't known until after a configuration is applied (such as a unique ID generated by the remote API when an object is created). ## Referring to Instances When `count` is set, Terraform distinguishes between the block itself and the multiple _resource or module instances_ associated with it. Instances are identified by an index number, starting with `0`. - `.` or `module.` (for example, `aws_instance.server`) refers to the resource block. - `.[]` or `module.[]` (for example, `aws_instance.server[0]`, `aws_instance.server[1]`, etc.) refers to individual instances. This is different from resources and modules without `count` or `for_each`, which can be referenced without an index or key. Similarly, resources from child modules with multiple instances are prefixed with `module.[]` when displayed in plan output and elsewhere in the UI. For a module without `count` or `for_each`, the address will not contain the module index as the module's name suffices to reference the module. -> **Note:** Within nested `provisioner` or `connection` blocks, the special `self` object refers to the current _resource instance,_ not the resource block as a whole. ## When to Use `for_each` Instead of `count` If your instances are almost identical, `count` is appropriate. If some of their arguments need distinct values that can't be directly derived from an integer, it's safer to use `for_each`. Before `for_each` was available, it was common to derive `count` from the length of a list and use `count.index` to look up the original list value: ```hcl variable "subnet_ids" { type = list(string) } resource "aws_instance" "server" { # Create one instance for each subnet count = length(var.subnet_ids) ami = "ami-a1b2c3d4" instance_type = "t2.micro" subnet_id = var.subnet_ids[count.index] tags = { Name = "Server ${count.index}" } } ``` This was fragile, because the resource instances were still identified by their _index_ instead of the string values in the list. If an element was removed from the middle of the list, every instance _after_ that element would see its `subnet_id` value change, resulting in more remote object changes than intended. Using `for_each` gives the same flexibility without the extra churn.