State is the topic that quietly decides whether you pass the HashiCorp Terraform Associate exam. It’s the single largest knowledge area in practice — backends, locking, drift, and the terraform state subcommands show up again and again — and it’s also the thing most likely to bite you in production. Engineers who treat terraform.tfstate as “just a cache file” eventually learn otherwise, usually at 2 a.m.
This guide covers state the way a platform engineer needs to understand it: what the file actually contains, why remote backends and locking exist, every state subcommand you’ll realistically use, and the patterns the Associate exam keeps coming back to.
What the State File Actually Is
Terraform is declarative: you describe the infrastructure you want, and Terraform figures out the operations to get there. To do that, it needs a record of what it created last time. That record is state.
The state file (terraform.tfstate) is a JSON document that maps every resource address in your configuration to the real-world object it manages:
{
"resources": [
{
"type": "aws_instance",
"name": "web",
"instances": [
{
"attributes": {
"id": "i-0abc123def456",
"private_ip": "10.0.1.42"
}
}
]
}
]
}
Three things follow from this, and all three are exam material:
- State is the source of truth for what Terraform manages. If a resource exists in the cloud but not in state, Terraform doesn’t know about it. If it exists in state but not in the cloud, Terraform plans to recreate it.
- State contains real attribute values — including sensitive ones. Database passwords, private keys, and connection strings set as resource attributes are stored in state in plain text. This is why state files must never be committed to version control and why backends supporting encryption at rest matter.
- State is required for
planto produce a diff. Plan output is a three-way comparison between your configuration, the state file, and (after refresh) the real infrastructure.
Local vs. Remote State
By default, Terraform writes terraform.tfstate to the working directory. That’s fine for a solo experiment and wrong for everything else:
- Two engineers running
applyfrom their laptops will overwrite each other’s state. - A laptop dies, and your only record of the infrastructure dies with it.
- Secrets sit unencrypted on every machine that has ever run
apply.
The fix is a remote backend — state stored in shared, durable, access-controlled storage. The ones worth knowing cold:
| Backend | Storage | Locking mechanism |
|---|---|---|
s3 | Amazon S3 | DynamoDB table (or S3 native locking with use_lockfile) |
azurerm | Azure Blob Storage | Native blob lease |
gcs | Google Cloud Storage | Native object locking |
remote / cloud | HCP Terraform | Built-in |
consul | Consul KV | Native sessions |
kubernetes | Kubernetes secret | Native lease |
A classic S3 backend configuration:
terraform {
backend "s3" {
bucket = "mycompany-tfstate"
key = "networking/prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Two details the exam likes:
- Backend blocks cannot use variables or expressions. Every value must be hardcoded or supplied via
-backend-configatinittime. - Changing backends requires re-running
terraform init, which offers to migrate existing state to the new backend.
State Locking
Locking prevents two concurrent operations from corrupting state. When you run plan or apply against a backend that supports locking, Terraform acquires a lock first; anyone else attempting a write operation gets an error until the lock is released.
What to remember:
- Locking happens automatically when the backend supports it — no flag needed.
-lock=falsedisables it (almost never a good idea outside of recovery scenarios).- If a process crashes and leaves a stale lock,
terraform force-unlock <LOCK_ID>releases it. The exam loves asking which command handles a stuck lock.
The terraform state Subcommands
These commands manipulate state without touching real infrastructure — that distinction is the heart of most exam questions about them.
| Command | What it does |
|---|---|
terraform state list | Lists all resource addresses in state |
terraform state show <addr> | Shows all recorded attributes of one resource |
terraform state mv <src> <dst> | Renames/moves a resource address in state (no resource change) |
terraform state rm <addr> | Removes a resource from state — Terraform forgets it, the real object survives |
terraform state pull | Streams the raw state JSON to stdout |
terraform state push | Uploads a local state file to the backend (dangerous; recovery tool) |
The two that deserve extra attention:
terraform state mv is how you refactor without destroying anything. Renamed a resource block? Moved it into a module? Without state mv (or a moved block in modern Terraform), the plan shows a destroy-and-recreate, because Terraform sees the old address disappearing and a new one appearing.
terraform state mv aws_instance.web module.compute.aws_instance.web
terraform state rm removes Terraform’s knowledge of a resource without deleting it. Use it when handing a resource over to a different state file or different tooling. The follow-up question is always: how do you get it back? terraform import (or an import block).
Drift, Refresh, and -refresh-only
Infrastructure changes outside Terraform — someone edits a security group in the console — and now state disagrees with reality. That’s drift.
- During
planandapply, Terraform refreshes state from real infrastructure before computing the diff. terraform apply -refresh-onlyupdates state to match reality without changing infrastructure — this replaced the standaloneterraform refreshworkflow (the old command still exists but is deprecated).- Drift detection in HCP Terraform runs these checks continuously on a schedule.
Sensitive Data in State: The Right Answers
When the exam (or your security team) asks how to handle secrets in state, the correct posture is layered:
- Use a remote backend with encryption at rest (S3 with
encrypt = true, Azure Storage SSE, GCS default encryption). - Restrict access to the backend with IAM — treat state like a secrets store, because it is one.
- Mark variables and outputs
sensitive = trueso values are redacted from CLI output (note: they are still in state in plain text —sensitiveaffects display, not storage). - Where possible, avoid passing secrets through Terraform at all — have resources pull from a secrets manager at runtime.
That third point is a top exam trap: sensitive = true does not encrypt anything in the state file.
How the Associate Exam Tests State
Across full-length practice exams, state questions cluster into five recognizable shapes:
- “Which command…” — moving, removing, listing, inspecting resources in state. If you can complete the table above from memory, these are free points.
- Backend behavior — what supports locking, what happens at
initwhen the backend changes, why backend blocks can’t contain variables. - What survives
state rm— Terraform forgets the resource; the real object is untouched. - Sensitive data — where secrets live, what
sensitive = trueactually does. - Recovery scenarios — stale locks (
force-unlock), corrupted local state (state pull/push), reattaching unmanaged resources (import).
The fastest way to find out which of these you’d miss under time pressure is to take a timed, full-length mock. The Sailor.sh Terraform Associate mock exam bundle weights state questions the way the real exam does and explains every distractor — which matters here more than anywhere, because state wrong-answers are usually plausible commands that do something subtly different.
Hands-On Drills Before Exam Day
Reading about state is not the same as having scars from it. Spend an evening on these:
- Initialize a project with a local backend, then migrate it to S3/GCS/Azure with
terraform initand watch the migration prompt. - Run
terraform state listandstate showon a real project until the address format is second nature. - Rename a resource block, run
plan, and watch the destroy/recreate. Fix it withterraform state mv, re-plan, and confirm zero changes. Repeat with amovedblock. terraform state rma resource, confirm it still exists in the cloud, then bring it back with animportblock.- Kill a
terraform applymid-run against a locking backend and recover withforce-unlock.
Frequently Asked Questions
Q: Is the state file required, or can Terraform work without it? A: It’s required. Terraform’s entire plan/apply model depends on mapping configuration to real resources through state.
Q: Can two workspaces share one backend?
A: Yes — CLI workspaces store separate state files under the same backend configuration (e.g., env:/staging/... keys in S3). Same backend, isolated state.
Q: What’s the difference between terraform state rm and terraform destroy -target?
A: state rm only removes Terraform’s record — the infrastructure survives. destroy -target actually deletes the real resource.
Q: How heavily does the Associate exam test state? A: It’s consistently one of the most-tested areas. Between backends, locking, subcommands, and drift, expect a meaningful slice of your exam to come from this one topic.
Next Steps
If state is solid, the rest of the exam gets dramatically easier. Work through the full picture with our Terraform Associate exam guide, test yourself with free interactive TF-004 practice questions or our 25-question written set, and when you’re ready for the real rehearsal, run timed full-length mocks with the Terraform Associate mock exam bundle until you’re consistently above 85%.