---
description: >-
  Count helps you efficiently manage nearly identical infrastructure resources
  without writing a separate block for each one.
---

# The `count` Meta-Argument

:::note
A given resource or module block cannot use both `count` and `for_each`.
:::

By default, a [resource block](../../language/resources/syntax.mdx) configures one real
infrastructure object. (Similarly, a
[module block](../../language/modules/syntax.mdx) 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.
OpenTofu has two ways to do this:
`count` and [`for_each`](../../language/meta-arguments/for_each.mdx).

If a resource or module block includes a `count` argument whose value is a whole number,
OpenTofu will create that many instances.

## Basic Syntax

`count` is a meta-argument defined by the OpenTofu 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](../../language/expressions/index.mdx).
However, unlike most arguments, the `count` value must be known
_before_ OpenTofu 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, OpenTofu 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`.

- `<TYPE>.<NAME>` or `module.<NAME>` (for example, `aws_instance.server`) refers to the resource block.
- `<TYPE>.<NAME>[<INDEX>]` or `module.<NAME>[<INDEX>]` (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.<NAME>[<KEY>]` 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.
