4.4.2. Expressions and Dynamic Configuration
💡 First Principle: Expressions let a single block adapt to its inputs — a conditional picks a value, a for transforms a collection, a dynamic block repeats nested configuration — so you describe variation declaratively instead of duplicating code.
The expression forms the exam expects: conditional condition ? true_val : false_val; for expressions that transform collections ([for s in var.list : upper(s)] for a list, {for k, v in var.map : k => v} for a map); splat var.list[*].id to pull an attribute from every element; and dynamic blocks to generate repeated nested blocks from a collection. String interpolation ("${var.name}-web") and heredoc strings round out the set.
# conditional
instance_type = var.env == "prod" ? "m5.large" : "t3.micro"
# for expression
upper_names = [for n in var.names : upper(n)]
# dynamic block
dynamic "ingress" {
for_each = var.ports
content {
from_port = ingress.value
to_port = ingress.value
}
}
⚠️ Exam Trap: dynamic blocks generate nested blocks (like multiple ingress blocks), not multiple resources — for multiple resources you use count/for_each. Confusing dynamic (repeats blocks within one resource) with for_each (repeats the resource itself) is a common error.
Reflection Question: When would you use a dynamic block versus for_each on the resource itself — what exactly is being repeated in each case?