count is the meta-argument for spawning multiple identical resources or modules from a single block. It expresses anything from 0 to N instances with minimal syntax.
Frequent exam topics include count.index, the splat operator ([*]), conditional creation (? 1 : 0), and how count differs from for_each.
count is a meta-argument that produces N identical instances from a single resource block. Just feeding it a number lets you toggle between 0 (no instance) and N. Every reference becomes indexed, so even with a single instance you must write [0].
count works on modules as well as resources. It cannot be combined with for_each on the same block, so you have to pick one. References take the form resource.type.name[index].attribute for resources, and module.name[index].output for modules.
The two patterns you'll use most often in practice are: toggling creation with a flag (count = var.enabled ? 1 : 0) and fanning out N identical resources (count = var.size). For the latter, weaving count.index into names and tags makes debugging much easier.
When a resource may have count=0, guard the reference (try or length check) to avoid evaluation errors during planning.
Basic examples for conditional creation and N-instance fan-out
# Example: create a single NAT Gateway only when the flag is on
variable "enable_nat" {
type = bool
default = false
}
resource "aws_nat_gateway" "nat" {
count = var.enable_nat ? 1 : 0
allocation_id = var.enable_nat ? aws_eip.nat[0].id : null
subnet_id = var.enable_nat ? aws_subnet.public[0].id : null
tags = {
Name = var.enable_nat ? "nat-0" : null
}
}
# Safe guard on the reference side
output "nat_gateway_id" {
value = try(aws_nat_gateway.nat[0].id, null)
}
# Example: spin up N identical web servers
variable "web_count" {
type = number
default = 3
}
resource "aws_instance" "web" {
count = var.web_count
ami = var.ami_id
instance_type = var.instance_type
tags = {
Name = format("web-%02d", count.index)
}
}
# Collect every ID at once via splat
output "web_ids" {
value = aws_instance.web[*].id
}count.index is the zero-based index unique to each instance. Use it for naming, pulling values out of arrays, and tagging. Don't forget: if you used count, references need [0] even when there's only one instance.
To pull a specific attribute from every instance in one go, the splat operator ([*]) is your friend. resource.type.name[*].attribute returns a list that's easy to pass to other modules or data sources.
count tends to produce large diffs when the count itself changes or when index-dependent attributes shift. In particular, if you assign names or CIDRs based on the index, reordering the source array forces many resources to be replaced.
The count value must be evaluable at plan time. If it depends on values that aren't known until apply (such as unknown attributes of other resources), planning fails with an error.
To keep destructive diffs in check: lock the input order (sort it), reach for for_each when you need identification that doesn't depend on the index, and design lifecycle blocks deliberately.
Both produce multiple instances, but they differ in how they handle identifiers and how resilient they are to changes. Use for_each when you want named, individualized instances; reach for count when you just need a fixed number of identical ones. This trade-off shows up often on the Associate exam.
| Aspect | count | for_each | Notes |
|---|---|---|---|
| Identifier | Sequential numbers (0..n-1) | Arbitrary key (string or number) | Key stability is what minimizes diffs |
| Ordering / Stability | Order-dependent (indexes get reassigned) | Key-dependent (order-independent) | for_each is resilient to reordering |
| Impact of Scaling | Trailing reductions or gaps trigger reassignment | Only the affected key is added or removed | for_each produces diffs that are easier to read in ops |
| Typical Use Case | N identical instances, toggle with a flag | Named subnets, map- or set-driven | Mix and match depending on the requirements |
| References | res[idx].attr / res[*].attr | res["key"].attr / res[*].attr | The syntax is the same for modules |
| Module Support | Yes | Yes | Both are available in the current stable release |
count works on modules too. Reference an individual instance with an index, like module.vpc[0], or grab them all at once via splat, like module.vpc[*].vpc_id. Module outputs become lists, which makes it safe to pipe them from a parent module into other modules or resources.
Just like resources, references take the module.vpc[0].output form even when count=1. When count=0 is possible, guard the access with try(module.vpc[0].output, null).
Conceptual diagram of count applied to a module
Associate
問題 1
You assign subnet CIDRs using count and count.index, driven by the order of the list var.cidr_blocks. If you reorder var.cidr_blocks, which describes Terraform's behavior best?
正解: A
count identifies instances by numeric index, so reordering the input shifts every index-based assignment (names, CIDRs, and so on), potentially causing widespread replacement. There is no mechanism that automatically preserves the previous mapping. To stabilize ordering, switch to for_each with stable keys.
Should I use count or for_each?
Use count when you just want to scale identical resources up and down by number. Use for_each when you want each instance managed by a stable identifier (a name or ID). If minimizing diffs and resilience to future changes matter, for_each is the safer choice.
Referencing a resource that may have count=0 throws an error. How do I prevent that?
Guard the reference site with try(resource[0].attr, null) or length(resource) > 0 ? resource[0].attr : null. When count=0, the resource reference is an empty list, so taking [0] directly throws an evaluation error.
When count is applied to a module, how do I reference its outputs?
Use module.mod[index].output for an individual reference, or module.mod[*].output to collect every output. Even with count=1 you must use [0], and if count=0 is possible, protect the access with try(module.mod[0].output, null).
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
HCL Syntax: Terraform's Configuration Language (2026)
HCL2 fundamentals for Terraform — blocks, attributes, expres...
Terraform Authoring & Operations Pro: Complete Guide (2026)
Tactics for the Terraform Pro exam — module authoring, works...
Terraform Providers: Plugin Management Fundamentals (2026)
Provider mechanics — required_providers, versions, mirrors, ...
Terraform Resource Blocks: Declarative Infra Units (2026)
Resource block fundamentals — addresses, references, common ...
Terraform Data Sources: Read-Only External Data (2026)
Data source basics — declaration, refresh behavior, dependen...