Execution Model
The modules runtime follows a build graph, walk graph pattern:Graph Construction
Each operation builds a graph through a pipeline of transforms:Key Graph Transforms
ConfigTransformer
Creates a vertex for eachresource block in configuration.
StateTransformer
Creates vertices for resource instances currently tracked in state.internal/terraform/transform_state.go
ReferenceTransformer
Analyzes references between resources and creates dependency edges.- Extract all
hcl.Traversalfrom expressions - Parse into
addrs.Referenceobjects - Map references to graph vertices
- Create edges from referencing vertex to referenced vertex
internal/terraform/transform_reference.go:112
ProviderTransformer
Associates each resource with its provider and ensures providers initialize first.internal/terraform/transform_provider.go:39
TransitiveReductionTransformer
Removes redundant edges while preserving reachability. If A→B→C and A→C both exist, the A→C edge is redundant and can be removed.Graph Validation
After construction, graphs must be validated:internal/dag/tarjan.go
Graph Walk
TheWalker executes vertices concurrently while respecting dependencies:
Walk Algorithm
Implementation details:- Per-vertex goroutines: Each vertex has a goroutine waiting on its dependencies
- Dependency tracking: Each vertex tracks channels from its dependencies
- Dynamic updates: Graph can be updated during walk via
Update() - Error propagation: Errors cause dependent vertices to skip execution
- Concurrent-safe: Uses mutexes to protect shared diagnostics map
internal/dag/walk.go:332
Vertex Execution
The walk callback executes each vertex:Evaluation Context
TheEvalContext provides shared state during execution:
BuiltinEvalContext- Production implementation with full functionalityMockEvalContext- Test implementation
EnterPath():
Dynamic Expansion
Resources withcount or for_each expand dynamically:
- Initial Graph
- After Expansion
Single vertex for the resource block.
- Has its own root node
- Is walked using the same algorithm
- Returns diagnostics to parent walk
internal/terraform/transform_expand.go
Expression Evaluation Flow
Evaluating a resource configuration: Steps:- Analyze - Extract references from expressions
- Resolve - Look up each reference in state/config
- Build context - Create
hcl.EvalContextwith values - Evaluate - HCL evaluates expression
- Return - Result flows back to vertex
internal/lang/eval.go
Concurrent State Access
Multiple vertices may access state concurrently:- Read safety: Multiple concurrent reads are safe
- Write safety: Writes are exclusive
- Consistency: State snapshots are consistent
Performance Characteristics
Graph Construction
- Complexity: O(V + E + T*E) where T is number of transforms
- Bottlenecks: ReferenceTransformer (O(V*R) where R is references per vertex)
- Optimization: Reference map caches lookups
Graph Walk
- Parallelism: Up to
parallelismvertices execute concurrently (default 10) - Overhead: V*2 goroutines created regardless of parallelism
- Scheduling: Automatic based on dependencies
Memory Usage
- Graph: O(V + E) for vertices and edges
- Walker state: O(V) for per-vertex tracking
- Evaluation: O(V) for cached expression results
Comparison with Stacks Runtime
The modules runtime differs from the newer stacks runtime:| Aspect | Modules Runtime | Stacks Runtime |
|---|---|---|
| Graph | Explicit, pre-built | Implicit, dynamic data flow |
| Concurrency | Walker-controlled | Promise-based |
| State | Shared mutable EvalContext | Immutable method calls |
| Scheduling | Static dependency graph | Dynamic call graph |
| Expansion | Graph-based sub-graphs | Lazy instance creation |
Further Reading
Graph Evaluation
Deep dive into graph algorithms
Dependency Resolution
How references become edges