What is the Resource Graph?
The resource graph is a directed acyclic graph (DAG) that Terraform constructs to represent the relationships between all the objects in your configuration. The graph determines the order in which operations are performed and enables parallel execution when possible.Every Terraform operation (plan, apply, destroy, etc.) builds its own graph tailored to that specific operation. The graph structure varies based on what needs to be accomplished.Source:
docs/architecture.mdGraph Components
Vertices (Nodes)
Vertices represent objects or actions in your infrastructure:- Resource Instances - Individual
resourceblocks or their instances (fromcount/for_each) - Provider Configurations - Provider initialization and configuration
- Module Instances - Module boundaries and expansion points
- Output Values - Output value evaluation
- Variables - Input variable evaluation
- Data Sources - Data source reads
internal/terraform/
Edges
Edges represent “must happen after” relationships:- Resources are created before their dependents
- Providers are initialized before being used
- Dependencies are destroyed after their dependents
Terraform uses dependency order, not execution order. The graph walker respects edges but may execute multiple vertices concurrently when they have no dependencies between them.
DAG Implementation
Terraform’s DAG is implemented ininternal/dag:
dag/dag.go and dag/graph.go
Why Acyclic?
Graphs must be acyclic (no cycles) because cycles would create impossible dependency situations:Graph Building Process
Graphs are built using the Transform pattern, where a series of graph transformers progressively build up the graph.Apply Transforms
Run a sequence of
GraphTransformer implementations that each modify the graph.graph_builder.go
Key Graph Transforms
Different transforms build different parts of the graph:| Transform | Purpose | Implementation |
|---|---|---|
ConfigTransformer | Add vertices for resource blocks | transform_config.go |
StateTransformer | Add vertices for resources in state | transform_state.go |
ReferenceTransformer | Create dependency edges from references | transform_reference.go |
ProviderTransformer | Associate resources with providers | transform_provider.go |
ModuleVariableTransformer | Handle module input variables | transform_module_variable.go |
OutputTransformer | Add output value vertices | transform_output.go |
TransitiveReductionTransformer | Optimize by removing redundant edges | transform_transitive_reduction.go |
docs/architecture.md
Example: Plan Graph Building
The plan graph builder applies transforms in this order:graph_builder_plan.go
Dependency Detection
Terraform automatically detects dependencies through reference analysis.Implicit Dependencies
Dependencies are inferred from resource references:ReferenceTransformer analyzes expressions to find references:
Parse Expressions
Extract all references from each resource’s configuration using
lang.References.Explicit Dependencies
Usedepends_on for dependencies that can’t be inferred:
Graph Walking
Once built, the graph is “walked” to execute operations:dag/walk.go
Walk Algorithm
The walk algorithm fromdag.AcyclicGraph.Walk:
Concurrency Control
The graph walker manages concurrency:graph_walk.go and context.go
Vertex Execution
Each vertex type has its own execution logic:NodePlannableResourceInstance.Execute- Plan a resourceNodeApplyableResourceInstance.Execute- Apply changes to a resourceNodeDestroyResourceInstance.Execute- Destroy a resource
docs/architecture.md
Execution Steps Example
During plan operation, resource instance execution:Evaluate Configuration
Evaluate attribute expressions, fetching values from dependencies via EvalContext.
docs/architecture.md
Dynamic Graph Expansion
Some vertices dynamically expand into subgraphs during execution.Count and For-Each
Resources withcount or for_each expand dynamically:
count may reference other resources whose values aren’t known when the main graph is built:
GraphNodeDynamicExpandable to create subgraphs.
Source: docs/architecture.md
Graph Types by Operation
Different operations use different graph builders:- Plan Graph
- Apply Graph
- Destroy Graph
- Validate Graph
Purpose: Calculate proposed changesKey vertices:
- Configuration resources (from .tf files)
- State resources (from state file)
- Providers
PlanGraphBuilderVisualizing Graphs
Terraform can output graph visualizations:Graph DOT Output
Implementation ingraph_dot.go generates Graphviz DOT format:
Graph Optimization
Transitive Reduction
TheTransitiveReductionTransformer removes redundant edges:
Before optimization:
- Graph visualization clarity
- Walk performance (fewer edges to check)
- Memory usage
Error Handling
Graph walking stops on errors:Dependent vertices are skipped when upstream vertices fail. Their diagnostics are excluded from the final error report since they’re caused by upstream failures.Source:
dag/walk.goReal-World Example
Given this configuration:- Initialize
provider.aws - Create
aws_vpc.main - Create
aws_subnet.app - Create
aws_instance.web[0]andaws_instance.web[1]in parallel
Best Practices
Let Terraform Detect Dependencies
Let Terraform Detect Dependencies
Use resource references instead of
depends_on whenever possible:Avoid Circular Dependencies
Avoid Circular Dependencies
Design your infrastructure to avoid cycles:Use security group rules instead to break the cycle.
Use Graph Visualization for Debugging
Use Graph Visualization for Debugging
When dependency issues occur, visualize the graph:
Understand Parallelism Trade-offs
Understand Parallelism Trade-offs
Higher parallelism = faster execution but:
- May hit API rate limits
- Uses more memory
- Harder to debug with concurrent errors
Common Graph Issues
Cycle Errors
Missing Dependencies
depends_on or reference the resource attribute.
Over-parallelization
terraform apply -parallelism=5
Next Steps
State Management
Learn how state is accessed and updated during graph walks