State & drift: how Terraform remembers
In the last lesson, Terraform somehow knew that your already-created bucket "matched the configuration" and needed no changes. How? It keeps a memory of what it has built, called state. State is the most powerful and the most dangerous concept in Terraform — mishandle it and you can corrupt or even destroy real infrastructure — so this lesson treats it carefully.
What state is and why it must exist
When Terraform runs plan, it needs to answer "what's the difference between my code (desired) and reality (current)?" To do that, it needs to know which real cloud resources correspond to which blocks in your code. It records this mapping in a state file (by default a local file named terraform.tfstate): a JSON document listing every resource Terraform manages, its real cloud ID, and its current attributes.
State is the bridge between your code and the real world:
Without state, Terraform couldn't tell the difference between "this resource already exists and is fine" and "I need to create a brand-new one." When you ran plan after apply and got "No changes," Terraform compared your code → state → reality and found them all aligned. State is what makes that comparison possible.
Why state is dangerous
State's power is also its peril:
- It's the source of truth for the mapping. If the state file is lost or corrupted, Terraform forgets it ever built your infrastructure. Run
applyand it may try to create everything again (duplicates) or, worse, lose track of resources entirely. - It can contain secrets. State stores resource attributes, and some of those are sensitive (database passwords, keys). A plain-text state file is a secret you must protect.
- It must not be edited by hand. The state file is Terraform's brain. Editing it manually almost always corrupts the mapping. There are proper commands for the rare cases you need to manipulate it; never open it in a text editor and "fix" it.
:::note Never commit local state to git
A local terraform.tfstate file should not be committed to a git repository: it can contain secrets, and if two people each have their own copy, their views of reality diverge instantly. The solution is remote state, covered next — and it's mandatory for any real team.
:::
Remote state and locking: making state safe for teams
A local state file works for a solo experiment but breaks the moment two people (or a pipeline) work on the same infrastructure: whose copy is correct? The fix is remote state — storing the state file in a shared, central location (typically an object-storage bucket like S3) that everyone and every automation reads from. Now there is one authoritative state, not many divergent copies.
Remote state brings a second essential feature: state locking. Imagine two engineers run apply at the same moment; they'd race to change the same resources and corrupt the state. Locking prevents this: when someone starts an operation, Terraform places a lock so no one else can run a conflicting operation until it finishes. One change at a time, safely.
:::tip The team-ready setup For anything beyond a personal experiment: use remote state with locking. Store state centrally (so there's one source of truth and it's backed up), encrypt it (it may hold secrets), and enable locking (so concurrent applies can't corrupt it). This is the standard, durable foundation every Terraform team starts from. (The exact backend you choose — which bucket, which lock mechanism — is dated detail.) :::
Drift: when reality wanders away from code
Now the other half of the lesson. Drift is what happens when the real infrastructure changes outside of Terraform — so reality no longer matches your code or your state. The usual cause is a human: someone goes into the console and manually tweaks a setting (opens a port, resizes a server, changes a tag) to fix something quickly, bypassing the code.
Why drift is a problem:
- Your code is supposed to be the source of truth, but now it lies — it describes something that isn't real anymore.
- The next person who runs
applybased on the code may undo the manual fix (Terraform reconciles reality back to the code), causing a surprise outage. Or the manual change creates a security hole that the code review never saw.
Terraform can detect drift: running terraform plan compares code, state, and the live reality, and if someone changed something by hand, the plan will show it as a change Terraform wants to "correct." That's a signal that someone went around the code.
The cultural fix matters more than the tooling: once infrastructure is managed by code, all changes go through the code. No more reaching into the console to "just quickly fix" something — that quick fix is drift, and it erodes the entire benefit of IaC. (This discipline is exactly what GitOps, in Chapter 5, enforces automatically.)
Why it matters
State is Terraform's memory — a file mapping your code's resources to real cloud IDs — and it's what lets plan compute differences and stay idempotent. It's also dangerous: lose it and Terraform forgets your infrastructure; it may hold secrets; and it must never be hand-edited. For any team, use remote state with locking so there's one authoritative, backed-up, encrypted copy and concurrent applies can't corrupt it. Drift is when reality changes outside Terraform (usually a manual console tweak); terraform plan detects it, but the real fix is discipline — all changes go through the code. With state understood, you can safely grow beyond a single file: the next lesson is how to organize and reuse infrastructure with modules.
Next: Modules & composition →