The Dependency Graph
Before Terraform executes anything, it constructs an internal graph where every resource, data source, module call, and output is a node, and edges represent dependency relationships between them. This graph is a directed acyclic graph (DAG) — directed because dependencies point one way, acyclic because Terraform would refuse to proceed if it detected a circular reference. The graph is what makes Terraform's execution order correct without a human ever specifying it explicitly: Terraform performs a topological sort of the graph so that every resource is created only after everything it depends on already exists.
Cricket analogy: Like a tour selection committee building a depth chart where a reserve wicketkeeper can only be picked after the primary keeper's fitness is confirmed — a directed, non-circular chain of decisions that determines the batting order without a human manually sequencing every pick.
Why the Graph Enables Parallelism
Because the graph captures exactly which resources depend on which others, Terraform can safely run independent branches of the graph in parallel rather than strictly serially. If a configuration creates ten unrelated S3 buckets, none of which reference each other, Terraform's graph walker will create them concurrently (up to the -parallelism limit, default 10), dramatically reducing apply time compared to a naive sequential approach. Only nodes with an actual dependency edge between them are forced into sequential order.
Cricket analogy: Like a groundstaff crew painting boundary markers at ten unrelated grounds simultaneously since none depend on each other, versus sequentially resurfacing one pitch's layers which must happen strictly in order — parallelism only where there's no real dependency.
Visualizing and Inspecting the Graph
Terraform can render its internal graph with terraform graph, which outputs DOT format suitable for tools like Graphviz. This is invaluable for debugging unexpected ordering, understanding why a resource is being replaced before another is created, or explaining to a new team member how a complex module's resources interrelate. During destroy operations, the graph is walked in reverse order, so dependents are destroyed before their dependencies to avoid leaving orphaned references.
Cricket analogy: Like a coach rendering a visual depth chart to debug why a young batsman was promoted before a senior one, useful for explaining team selection logic to a new selector, just as terraform graph outputs DOT format for Graphviz to visualize ordering.
$ terraform graph | dot -Tsvg > graph.svg
$ terraform graph
digraph {
compact = "true"
newrank = "true"
subgraph "root" {
"[root] aws_instance.web" -> "[root] aws_security_group.web_sg"
"[root] aws_instance.web" -> "[root] aws_subnet.public"
"[root] aws_security_group.web_sg" -> "[root] aws_vpc.main"
"[root] aws_subnet.public" -> "[root] aws_vpc.main"
}
}Think of the dependency graph like a recipe's mise en place: some steps (chopping vegetables, preheating the oven) can happen simultaneously because they don't depend on each other, while others (plating the finished dish) must strictly wait until everything feeding into them is ready.
A dependency that exists only implicitly through a data source or external side effect — one that Terraform's expression evaluator can't see — won't appear as a graph edge. If resource B genuinely relies on resource A existing first but nothing in B's arguments actually references A, Terraform may attempt to create them in the wrong order or in parallel, causing a runtime failure. Use explicit depends_on for such cases.
- Terraform builds a directed acyclic graph (DAG) of every resource, data source, module, and output before executing any operation.
- A topological sort of the graph determines the order resources are created, updated, or destroyed.
- Independent branches of the graph run in parallel, up to the -parallelism limit (default 10).
- terraform graph renders the DAG in DOT format for visualization with tools like Graphviz.
- Destroy operations walk the graph in reverse, removing dependents before their dependencies.
- Hidden dependencies invisible to expression evaluation require an explicit depends_on to be captured as a graph edge.
Practice what you learned
1. What kind of graph structure does Terraform build internally to plan execution order?
2. What happens if Terraform's configuration contains a circular dependency?
3. Why can Terraform create multiple unrelated resources concurrently during apply?
4. In what order does Terraform traverse the graph during a destroy operation?
5. What is required to make Terraform respect a dependency that isn't visible through any argument reference?
Was this page helpful?
You May Also Like
Implicit vs Explicit Dependencies
Learn how Terraform automatically infers resource ordering from configuration references, and when you must override that inference with depends_on.
terraform init, plan, and apply
The three-command core workflow of Terraform: init downloads dependencies, plan previews changes, and apply executes them -- forming a safe, repeatable provisioning cycle.
count and for_each
Compare Terraform's two meta-arguments for creating multiple copies of a resource or module, and understand why for_each is usually the safer choice.
Resources and Resource Blocks
The resource block is Terraform's fundamental unit of infrastructure declaration, describing a single managed object like a virtual machine, network, or storage bucket.
Related Reading
Related Study Notes in DevOps
Browse all study notesNginx Study Notes
DevOps · 30 topics
DevOpsAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics