Request Flow
When you run a Terraform command liketerraform plan or terraform apply, the request flows through several layers:
CLI Layer
The CLI layer (internal/command/) handles:
- Parsing command-line arguments and flags
- Reading environment variables
- Constructing a
backendrun.Operationthat describes the action to take - Passing the operation to the selected backend
command package (see commands.go in the repository root).
Backend Layer
Backends (internal/backend/) determine where Terraform stores its state snapshots. The local backend also executes operations on behalf of most other backends:
- Retrieves current state using a state manager (
internal/states/statemgr) - Loads and validates configuration using the config loader (
internal/configs/configload) - Constructs a
terraform.Contextfor execution - Calls the appropriate context method (
Plan,Apply, etc.)
Configuration Loading
The configuration loader (internal/configs/configload.Loader):
- Takes a root module path as input
- Recursively loads all child modules
- Produces a
configs.Configrepresenting the entire configuration tree
internal/configs. Some parts remain as hcl.Body and hcl.Expression for later evaluation during graph walk.
Core Architecture Components
Terraform Context
Theterraform.Context (internal/terraform/context.go) is the main orchestrator:
- Plugin instances (providers and provisioners)
- Hooks for progress reporting
- Parallelism controls via semaphores
- Execution state through run contexts
Plan()- Creates an execution planApply()- Applies changes from a planValidate()- Validates configurationRefresh()- Updates state from real infrastructure
Graph-Based Execution
Terraform uses directed acyclic graphs (DAGs) to model dependencies and determine execution order:- Vertices represent operations (resource instances, providers, variables, etc.)
- Edges represent “happens after” dependencies
- Graph builders construct graphs using transforms
- Graph walkers execute vertices in dependency order
Graph Transforms
Graphs are built through a series of transforms (GraphTransformer interface):
ConfigTransformer- Creates vertices forresourceblocksStateTransformer- Creates vertices for resources in stateReferenceTransformer- Adds edges based on configuration referencesProviderTransformer- Associates resources with providersTransitiveReduction- Removes redundant edges
internal/terraform/graph_builder_plan.go, internal/terraform/graph_builder_apply.go
Graph Walk
The graph walk (internal/dag/walk.go) visits vertices in parallel while respecting dependencies:
- Starts from vertices with no dependencies
- Executes multiple vertices concurrently when possible
- Waits for dependencies before executing dependent vertices
- Collects diagnostics from all executions
- Halts if any vertex returns errors
V*2 goroutines (one per vertex, one dependency waiter per vertex) for maximum parallelism.
Vertex Execution
During the walk, each vertex that implementsGraphNodeExecutable has its Execute method called:
- Retrieving providers from
EvalContext - Reading current state
- Evaluating configuration expressions
- Calling provider plugin methods
- Updating plan or state
internal/terraform/node_resource_plan_instance.go:68
Dynamic Expansion
Some vertices expand into sub-graphs after evaluation:- Resources with
countorfor_eachinitially have one vertex perresourceblock - After evaluating the count/for_each expression, the vertex creates a sub-graph with one vertex per instance
- The sub-graph is walked using the same algorithm
GraphNodeDynamicExpandable trigger this behavior.
Expression Evaluation
Configuration expressions are evaluated during vertex execution:- Analyze expressions to find references (
lang.References) - Retrieve values for referenced objects from state
- Prepare function table with built-in functions
- Evaluate using HCL’s evaluation engine
cty.Value objects that are passed to providers.
See: internal/lang/eval.go
Plugin Protocol
Terraform communicates with provider plugins via gRPC:- Plugins are separate processes launched by Terraform
- Communication uses protocol buffers (
.protodefinitions) - Values are serialized using MessagePack or JSON
- Current protocol versions: 5.x and 6.x
State Management
State managers (internal/states/statemgr) handle state persistence:
statemgr.Filesystem- Localterraform.tfstatefiles- Remote state implementations - Cloud storage backends
- All implement
statemgr.Fullinterface - State is represented as
states.Stateobjects
Concurrency and Synchronization
Terraform uses several concurrency primitives:- Semaphores limit parallelism (default: 10 concurrent operations)
- Mutexes protect shared state via
states.SyncState - Graph walk automatically parallelizes independent operations
- Hooks are called synchronously during vertex execution
Architecture Principles
Separation of Concerns
- Configuration is separate from state
- Planning is separate from applying
- Graph building is separate from graph walking
- Core is separate from providers
Deterministic Execution
While the graph walk is concurrent:- Dependencies ensure correct ordering
- Same configuration + state → same plan
- Providers must be deterministic in planning
Extensibility
The plugin model allows:- Custom providers for any API
- Language-agnostic plugin development
- Version negotiation between core and plugins
Further Reading
Modules Runtime
Deep dive into traditional module execution
Stacks Runtime
New orchestration layer for stacks
Plugin Protocol
Provider communication specifications
Resource Lifecycle
How resources are created, updated, destroyed