Terraform Under the Hood: State, Graphs, and a Compiler-Inspired Execution Engine

DevOps Engineer
This article explains Terraform not as a user tool, but as a system: how it thinks, how it reasons, and how it executes.
1. The Fundamental Problem Terraform Solves
Before Terraform, infrastructure automation suffered from three structural problems:
No global view of infrastructure
No reliable mapping between code and real resources
No deterministic ordering or safe parallelism
2. Terraform’s Core Design Philosophy
Terraform is built on five non-negotiable principles:
Declarative intent, imperative execution
State is a first-class primitive
Dependency graph drives everything
Providers are isolated, replaceable plugins
Planning and execution must be separate phases
So, if we understand these five principles, we understand Terraform to a good extent.
3. Terraform as a Compiler for Infrastructure
Although Terraform is not a compiler but it behaves very much like a compiler than a scripting tool.
We can understand it through this analogy:
| Compiler Concept | Terraform Equivalent |
| Source Code | .tf files |
| AST | Parsed HCL configurations |
| Symbol Table | variables, locals, resources, modules |
| IR(Intermediate Representation) | Dependency Graph |
| Optimization Pass | Diff minimization |
| Execution | Provider API calls |
(I am sure this will remind everyone of Compiler Design 😅)
Note: Here, Diff minimization refers to the smallest and safest set of changes Terraform computes to make real infrastructure match the desired configuration.
So, this is how it goes:
A classic compiler: Source Code → AST → IR → Optimized IR → Machine Code
Terraform: .tf → Parsed Config → Dependency Graph → Execution Plan → API calls
4. Configuration Loading & HCL Evaluation
Parsing HCL
Terraform first parses all .tf files into an abstract syntax tree (AST). At this stage:
Only syntax is validated
No provider calls occur
No resources are evaluated
This allows Terraform to support:
Static analysis
Formatting (
terraform fmt)Validation without credentials
Expression Evaluation Model
Terraform uses a lazy, dependency-aware expression model:
Expressions are evaluated only when needed
References create implicit graph edges
Unknown values are allowed during planning
For example,instance_id = aws_instance.example.id
During planning, this value may be unknown, but Terraform still proceeds.
This design enables forward references and dynamic graphs.
5. Providers: The Plugin Boundary
Terraform core never talks to cloud APIs.
Providers are:
Separate binaries
Communicated with via gRPC
Versioned and schema-driven
Provider Responsibilities
Resource schemas
Defines the shape of each resource (attributes, types, optional/required fields, computed fields)
Tells Terraform what properties are available
CRUD operations
Create, Read, Update, Delete for each resource
Terraform calls these during
apply
Diff / Plan logic
Determine what changed between the desired state (
.tf) and the current stateUsed to generate the execution plan
Import behavior
Ability to import existing resources into Terraform state
Needed for resources that were created outside Terraform
State upgrade / migration paths
Handle provider version upgrades
Transform stored state so it remains compatible
Terraform core delegates all domain-specific logic to providers.
6. State: Terraform’s Memory & Authority
What State Really Is
It is a file that acts as Terraform’s memory of the infrastructure it manages.
It’s the source of truth for Terraform about what resources exist and how they are mapped.
State is a bidirectional mapping.
For example,aws_instance.example.id ↔ i-abcd123
Why Terraform Owns State
Terraform owns state because:
Providers cannot track cross-resource dependencies
Clouds do not expose dependency graphs
Drift detection requires historical knowledge
State enables precise diffs instead of blind recreation.
7. Backends and State Locking
Backends define:
Where state is stored
How it is locked
How concurrency is handled
Why Locking is Mandatory?
Terraform assumes exclusive mutation rights.
Without locking:
Two applies could destroy each other’s resources
Graph assumptions become invalid
Remote backends enforce locking via:
DynamoDB
Terraform Cloud
Native backend mechanisms
8. terraform init: System Bootstrapping
terraform init is Terraform’s bootstrap compiler phase. It prepares everything Terraform needs before it can understand, plan, or apply your infrastructure.
Just like a compiler must:
set up its environment
load libraries
prepare tooling
before compiling code, Terraform must initialize its working directory before doing anything else.
Configuration Scan & Root Module Assembly
Terraform first scans the working directory and constructs the root module:
All
.tffiles are loadedFiles are merged logically (order does not matter)
Only syntax and block structure are validated
No expressions are fully evaluated yet. Terraform is only building a structural model of the configuration.
Backend Resolution and State Writing
Terraform then initializes the backend:
Determines backend type (local, S3, Terraform Cloud, etc.)
Loads backend configuration
Establishes credentials
Verifies read/write permissions
At this stage:
No state is read
No locks are acquired
Terraform is only confirming where state will live and how it will be accessed later.
Provider Discovery & Dependency Resolution
Terraform identifies required providers from:
required_providersImplicit provider usage in resources
Terraform then:
Solves version constraints using semantic versioning
Selects exact provider versions
Downloads provider binaries
Verifies checksums
Providers are installed as isolated executables, not libraries.
Plugin Handshake & Schema Discovery
Terraform performs a gRPC handshake with each provider to:
Validate protocol compatibility
Retrieve resource schemas
Retrieve data source schemas
Register lifecycle capabilities
At this point Terraform learns:
Which attributes are computed
Which changes force replacement
What operations are supported
Module Installation & Graph Expansion
Terraform resolves all modules:
Registry modules
Git modules
Local modules
Each module is:
Downloaded
Version-pinned
Cached
Terraform expands modules recursively, but does not yet evaluate their contents.
Dependency Lock File Generation
Terraform writes .terraform.lock.hcl, recording:
Exact provider versions
Cryptographic checksums
9. terraform plan: The Reconciliation Engine
terraform plan is Terraform’s core reasoning phase.
It’s sole purpose is to figure out the smallest and safest set of changes needed to make the real infrastructure match what you want.
State Loading & In-Memory State Graph
Terraform:
Reads the current state from the backend
Loads it into memory
Converts it into an internal graph structure
Refresh: Reality Interrogation
Terraform:
Calls the provider’s Read function for each resource
Queries the real cloud APIs
Normalizes the responses into Terraform’s expected format
Expression Evaluation & Unknown Propagation
Terraform:
Evaluates expressions (
var.x,local.y, references)Does so lazily (only when needed)
Marks values as unknown if they depend on something not yet created
Dependency Graph Construction (DAG)
Terraform:
Builds a Directed Acyclic Graph
Each node = a resource instance
Each edge = a dependency (explicit or implicit)
This graph:
Determines creation / update order
Enables safe parallel execution
Prevents cycles
Diff Computation Engine
Terraform:
Compares the desired configuration graph
Against the current (refreshed) state graph
At the attribute level
For each resource, Terraform decides:
No change
In-place update
Replace (destroy + create)
This is where minimal, safe changes are determined.
Plan Serialization
Terraform:
Produces an immutable execution plan
Stores it in a binary plan file
This plan:
Is deterministic
Can be reviewed
Can be applied later without recomputation
10. terraform apply: Graph Execution Engine
terraform apply is Terraform’s transactional execution phase. It is the phase where Terraform actually changes real infrastructure based on a previously computed plan.
State Lock Acquisition
Before making any changes, Terraform:
Acquires an exclusive lock on the state
Prevents other Terraform runs from modifying the same infrastructure at the same time
Why this matters:
Avoids race conditions
Prevents state corruption
Notes:
Locking depends on the backend (S3 + DynamoDB, Terraform Cloud, etc.)
Local state has implicit locking
Execution Graph Walk
Terraform:
Uses the dependency graph (DAG) built during planning
Walks the graph in a safe order
Executes independent nodes in parallel
Example:
Multiple EC2 instances in the same subnet can be created at the same time
A database waits until its network dependencies exist
This ensures:
Correct ordering
Faster execution
Provider RPC Invocation
For each node in the execution graph, Terraform:
Calls the provider’s Create / Update / Delete methods
Communicates via gRPC
Providers translate these calls into real API requests (AWS, Azure, etc.)
Terraform Core:
Orchestrates
Does not know API details
Providers:
- Perform the actual work
Incremental State Mutation
After each successful operation, Terraform:
Immediately updates the in-memory state
Persists the updated state to the backend
Why this is important:
If execution stops midway, Terraform still knows what succeeded
Prevents redoing completed work
This is critical for crash recovery and retries.
Failure Semantics
Terraform does not provide automatic rollback.
If something fails:
Successfully applied changes are kept
Failed operations remain unapplied
State reflects partial success
Terraform’s recovery model is:
Fix the problem → re-run terraform plan → re-run terraform apply
Why this design:
Many infrastructure APIs do not support atomic transactions
Rollbacks can be dangerous or ambiguous
11. Lifecycle Controls
Terraform provides lifecycle rules that let you influence execution strategy i.e. how resources are created, updated, or destroyed, without changing Terraform’s core model of infrastructure.
They affect:
Order of operations
Safety guarantees
Which changes to act on
They do not change:
Dependency graph structure
Resource identity
Terraform’s state model
Common lifecycle settings: create_before_destroy, prevent_destroy, ignore_changes
12. Terraform’s True Strength
Terraform’s power is not provisioning.
It is accurate, minimal change computation at scale.
Terraform answers with precision:
“What is the smallest possible set of safe operations to reach the desired state?”
That is its real innovation.
Conclusion:
Terraform is:
A compiler for infrastructure
A graph execution engine
A state reconciliation system
It does not manage servers.
It manages truth.
Connect with me on LinkedIn: https://linkedin.com/in/scoder17
Follow me on GitHub: https://github.com/scoder17
Connect with me on Twitter/X: twitter.com/scoder17_
Subscribe me here: https://scoder17.hashnode.dev/


