Terraform architecture: configuration, providers, plans and state
Follow Terraform from configuration through its dependency graph, provider calls and saved plan. Explain unknown values, replacement and partial apply without treating a plan as a transaction.
TL;DR: Terraform combines configuration, prior state and provider observations to propose infrastructure changes. Providers implement resource-specific API operations; Terraform orders dependencies. A saved plan identifies proposed actions, but applying it can still fail partway through and leave real changes to reconcile.
Each input answers a different question
Configuration describes the intended managed resources and relationships. State connects Terraform resource addresses to remote objects and retains information used for planning. Providers define resource schemas and communicate with external APIs. The backend stores state and may support coordination such as locking.
For example, aws_subnet.app is a configuration address. State can associate that address with a particular subnet ID. The provider reads the remote subnet and reports attributes relevant to its schema. A variable file supplies values to configuration; it is not a replacement for the address-to-object mapping in state.
The Terraform dependency graph documentation explains how references create ordering relationships. Terraform can operate on independent graph nodes concurrently, so file order is not a general execution-order mechanism.
The loop is bounded by an invocation or an external automation system. Terraform CLI does not continuously repair drift merely because a configuration file exists.
Read a plan as a set of consequences
| Plan observation | Meaning to establish | Question before approval |
|---|---|---|
| In-place update | Provider expects to change the existing object | Could the service restart or lose connections? |
| Replacement | Existing object must be replaced under the planned lifecycle | Can both versions coexist, and what happens to data? |
| Known after apply | Value cannot yet be determined | Does that uncertainty affect a policy or dependency decision? |
| Destroy | A managed object is to be removed | Was the configuration intentionally removed or the address changed? |
| No changes | No action under this plan's inputs and observations | Were refresh, workspace and variable inputs correct? |
A zero-change plan does not prove every property of the external system is correct. Providers only model supported attributes, and data outside Terraform's management boundary may differ. Conversely, a plan with changes might reflect an address refactor rather than an intended replacement. Use supported migration mechanisms for address changes.
Bind review to the planned artifact
These commands assume an initialized, authorized lab workspace. Planning reads infrastructure and state; applying would mutate them, so the example stops at review.
terraform validate
terraform plan -out=review.tfplan
terraform show -no-color review.tfplan
The saved plan contains the proposed action set and associated inputs. Treat it as sensitive because values hidden in terminal output may still be present in the plan file. Restrict storage and retention. The plan command documentation describes saved versus speculative plans and the risks of options such as disabling refresh or targeting only part of the graph.
In a delivery workflow, apply the exact reviewed plan under the intended workspace and identity, with appropriate freshness checks. A speculative pull-request plan followed by a new unrestricted apply can produce a different decision if inputs or remote state changed between the two operations.
A partial apply is a recovery problem
Assume a run creates a network, then fails while creating a database because quota is exhausted. Terraform is not an all-or-nothing transaction across provider APIs. The network can exist after the failure, and state may record completed operations.
Read the failure output, inspect state and relevant remote resources, and generate a fresh plan after resolving the cause. Do not delete the state file to “start again.” That discards management relationships while leaving resources behind. If the interruption happened during an ambiguous API outcome, carefully reconcile which object exists before retrying or importing it.
A plan can also become stale when another process updates the same state. That is why state locking and saved-plan freshness belong in the architecture rather than being treated as optional pipeline polish.
Dependencies express real readiness only when modeled
Referencing a subnet ID establishes that the subnet must be created before a resource that needs it. It does not necessarily prove every network route or external service is ready for application traffic. Use explicit dependencies when a genuine hidden dependency exists, but avoid making the whole graph sequential without a reason.
Provisioning and configuring a service are different responsibilities. Terraform may create VMs while Ansible configures their operating system. Decide which tool owns each property. Two tools repeatedly changing the same setting make drift difficult to interpret.
Explain the apparent contradiction
Self-check: a reviewed plan says a database will be replaced even though the desired instance count is unchanged. What should you examine?
Inspect which changed attribute requires replacement, the provider version, the resource address and lifecycle settings. Capacity count does not establish object identity. Determine whether replacement is intended, whether storage survives, and how clients move to the new instance. Refuse to summarize the plan as “one instance before and after, therefore no impact.”
Read state and drift for ownership and observation, then use immutable replacement to reason about a safe cutover.