The dependency graph and execution

Terraform · Expert · 12 min

Explains slow plans, odd ordering, "known after apply" cascades and cycle errors.

Terraform builds a directed acyclic graph from your configuration: nodes for resources, data sources, providers, variables, locals, outputs and modules; edges from references and depends_on. terraform graph prints it in DOT format.

Execution walks the graph concurrently: any node whose dependencies are done can run, up to -parallelism=10 operations at a time by default. Lower it when an API rate-limits you; raise it for large flat states.

Order details:

  • Destroys run in the reverse of creation order.
  • With create_before_destroy, the replacement is created before the old object (and everything depending on it) is destroyed; the setting propagates to dependencies to keep the graph acyclic.
  • A cycle error means two objects depend on each other through references; break it by splitting a resource (e.g. separate security group rule resources instead of inline rules).

Unknown values: attributes computed by the provider during apply are unknown at plan time. They propagate: anything derived from them becomes (known after apply), which can force replacements to look broader than they are, and make count/for_each impossible to evaluate ("value depends on resource attributes that cannot be determined until apply"). Fix by keying on known inputs, or splitting into two applies with -target as a last resort.

Plan time grows with the number of resources and the API calls refresh makes; splitting large states is the main cure.

Example

terraform graph -type=plan | dot -Tsvg > graph.svg   # needs graphviz

terraform apply -parallelism=4        # gentler on rate-limited APIs

# Classic unknown-value error:
# Error: Invalid for_each argument
#   The "for_each" map includes keys derived from resource attributes
#   that cannot be determined until apply...
# Fix: key on input values (names), not on IDs created in the same run.

# Cycle example message:
# Error: Cycle: aws_security_group.a, aws_security_group.b
# Fix: move the cross-references into separate aws_vpc_security_group_ingress_rule resources.

Remember

  • References and depends_on form a DAG walked in parallel (default 10)
  • Unknown values propagate and can block count/for_each
  • Cycles are fixed by splitting resources

Watch out for

  • Keying for_each on IDs of resources created in the same apply.

Check yourself

  1. Why does for_each = { for i in aws_instance.web : i.id => i } fail on a fresh apply?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: developer.hashicorp.com/terraform/internals/graph

Builds on

Unlocks

Nothing builds on this yet.