π― Goal: Move beyond basic resources β use meta-arguments to build dynamic, reliable, production-grade configs.
β Youβll master:
- β
countvsfor_each: When & why to use each- β
depends_on: Explicit dependencies (no more βrace conditionsβ)- β
lifecycle: Protect critical resources (prevent_destroy,create_before_destroy)- β Real-world patterns (S3 buckets, IAM users, multi-region)
β Without meta-arguments:
β 10 copies of
aws_s3_bucketblocksβ Resource creation order = guesswork
β Accidental
terraform destroy= production outage
β With meta-arguments:
β DRY: One block β N resources
β Reliable: Control dependencies & lifecycle
β Safe: Guardrails against human error
| Meta-Argument | Input Type | Use Case | Stability | Production Ready? |
|---|---|---|---|---|
count |
number |
Fixed N identical resources (e.g., dev instances) | β οΈ Low (index drift) | β Avoid in prod |
for_each |
map / set(string) |
Named resources (e.g., env-specific buckets) | β High (key-based) | β Preferred |
depends_on |
[resource] |
Hidden dependencies (e.g., IAM β S3) | β | β Use sparingly |
lifecycle |
Block | Protect resources, ignore drift | β | β Critical for prod |
π― Golden Rule:
βUse
for_each90% of the time βcountonly for simple, temporary resources.β
count vs for_each β S3 Bucket Labvariables.tf β Input Data# πΈ List (for `count`)
variable "bucket_names_list" {
type = list(string)
default = ["dev-logs", "staging-logs"]
}
# πΈ Set (for `for_each`)
variable "bucket_names_set" {
type = set(string)
default = toset(["prod-logs", "dr-logs"]) # β Dedupes automatically
}
# πΈ Map (for advanced `for_each`)
variable "bucket_configs" {
type = map(object({
tags = map(string)
acl = string
}))
default = {
"audit" = {
tags = { Purpose = "Compliance" },
acl = "private"
}
"backup" = {
tags = { Purpose = "Disaster Recovery" },
acl = "private"
}
}
}
count β Simple, but Fragilemain.tf