Two blocks, five objects
The count that matters is the instances, not the blocks in the file
zones = ["a", "b", "c"]
resource "aws_subnet" "private" {
for_each = toset(zones)
}
resource "aws_instance" "web" {
count = 2
} Count the objects a configuration creates, rather than the blocks it contains. Bind any variables above the blocks and the count and for_each expressions are evaluated for real.
Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.
The answer appears here
Paste on the left and press Calculate. Nothing leaves this tab.
Nothing else to flag.
No formatting problems, and nothing the rules object to. Worth remembering what that covers: this reads the file you pasted, not the account or cluster it will be applied to.
No finding matches that filter.
Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.
The count that matters is the instances, not the blocks in the file
zones = ["a", "b", "c"]
resource "aws_subnet" "private" {
for_each = toset(zones)
}
resource "aws_instance" "web" {
count = 2
}Plans as a destroy of everything that exists, and looks like a deliberate removal
enabled = false
resource "aws_instance" "bastion" {
count = enabled ? 1 : 0
}Terraform needs a map or a set: a list has positions, which is what for_each avoids
resource "aws_subnet" "private" {
for_each = "a-string"
}These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
The bottleneck is usually the provider's API rate limit rather than Terraform. More concurrency produces throttling and retries, which is slower.
Instead:Check the provider's limits first. If the apply is genuinely too big, split the state instead.
A list has positions, not keys, and for_each exists to avoid positions. Terraform refuses rather than converting.
Instead:Wrap it in toset(), and check the count afterwards because toset drops duplicates.
An empty collection means zero instances, which plans as a destroy of everything that exists. It looks identical to a deliberate removal.
Instead:Add a validation block on the variable, and read the destroy count in every plan before approving it.
A file with four resource blocks can create four objects or four hundred. The number that matters is never visible in the file.
So three hundred instances is thirty rounds, plus whatever the provider's rate limiter does to them. Raising -parallelism is the obvious move and usually the wrong one: the common result is throttling and retries, which is slower than the limit you were trying to beat.
count = 0 or an empty for_each is legal and means the resource is not created. If instances already exist, that plan destroys all of them. It is the shape of an accidental teardown when a variable arrives empty from CI, and the plan looks exactly like a deliberate removal.
It needs a map or a set of strings. A list has positions rather than keys, and positions are the thing for_each exists to avoid, so Terraform refuses rather than converting. toset() is the usual fix, and it also collapses duplicates, which silently reduces the count.
count = var.enabled is an error even though the intent is obvious. The conditional form count = var.enabled ? 1 : 0 is what Terraform wants, and it is the one case where count beats for_each.
If the count depends on something Terraform cannot know until it applies, it cannot tell you the number either. That is why a plan sometimes cannot say what it will do: it does not know how many of a thing there will be.
A module with count = 3 containing a resource with for_each over five items creates fifteen objects. This page counts the blocks you paste, so a module call counts as its own expansion rather than as everything inside it.