8 — Conditionals¶
Folder: none yet — paste this into a scratch root.
Terraform has no if statement. Conditional creation is done with count = <bool> ? 1 : 0,
which turns a resource into either a one-element or a zero-element list of instances.
The code¶
variable "create_backup_file" {
type = bool
default = false
}
resource "local_file" "backup" {
count = var.create_backup_file ? 1 : 0
filename = "/tmp/backup.txt"
content = "This only exists if the flag is true."
}
terraform plan # default false — 0 resources, nothing created
terraform plan -var="create_backup_file=true" # now shows 1 to add
count = 0 is an empty list, not an empty resource¶
This is the part that trips people up. Reference it the obvious way, on purpose:
output "backup_path" {
value = local_file.backup.filename # WRONG when count is used — no index given
}
Expect an error telling you an index is required. The resource is not a single object with
empty attributes — it is a list of instances that happens to have zero elements. There
is no .filename to read because there is no instance to read it from.
The fix has to handle the empty case explicitly:
output "backup_path" {
value = length(local_file.backup) > 0 ? local_file.backup[0].filename : "not created"
}
Guard propagation¶
The consequence scales badly, and it's worth internalising here where it's cheap. Every
consumer of a conditionally-created resource has to re-apply the guard. The condition
lives in one place; the defensive length() > 0 checks spread to everywhere that reads it.
In the sandbox this is exactly the bug that cost a full debugging session: a module
for_each'd over a filtered map produces zero instances when everything is disabled, and
each downstream reference has to cope with the empty map independently. See
Session 2 and the
guard propagation row in the concept index.
The mitigation is to filter in locals rather than inside the module, so the module never
knows it was conditional — but the guard still has to be re-applied by each consumer of the
filtered collection.
Real-world shape¶
The pattern in production code usually reads:
…with every reference to it written as google_sql_database_instance.main[0] guarded by
the same flag, or one(google_sql_database_instance.main) which returns null instead of
erroring on an empty list.
Key takeaway¶
A conditional resource is a zero-or-one-element list, not a nullable object. The condition gets written once; coping with the empty case gets written everywhere the resource is read. That asymmetry is the entire lesson, and forgetting it is what turns a one-line feature flag into a debugging session.
Theory: §8 Expressions & conditionals · Quiz: Variables, expressions & guards · Next: Lifecycle