Back to Blog

Terraform State Management Explained: Remote Backends, Locking & State Commands

A practitioner's guide to Terraform state — what the state file actually contains, remote backends with locking, every terraform state subcommand, and how the Terraform Associate exam tests it.

By Sailor Team , June 10, 2026

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:

  1. 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.
  2. 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.
  3. State is required for plan to 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 apply from 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:

BackendStorageLocking mechanism
s3Amazon S3DynamoDB table (or S3 native locking with use_lockfile)
azurermAzure Blob StorageNative blob lease
gcsGoogle Cloud StorageNative object locking
remote / cloudHCP TerraformBuilt-in
consulConsul KVNative sessions
kubernetesKubernetes secretNative 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-config at init time.
  • 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=false disables 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.

CommandWhat it does
terraform state listLists 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 pullStreams the raw state JSON to stdout
terraform state pushUploads 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 plan and apply, Terraform refreshes state from real infrastructure before computing the diff.
  • terraform apply -refresh-only updates state to match reality without changing infrastructure — this replaced the standalone terraform refresh workflow (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:

  1. Use a remote backend with encryption at rest (S3 with encrypt = true, Azure Storage SSE, GCS default encryption).
  2. Restrict access to the backend with IAM — treat state like a secrets store, because it is one.
  3. Mark variables and outputs sensitive = true so values are redacted from CLI output (note: they are still in state in plain textsensitive affects display, not storage).
  4. 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:

  1. “Which command…” — moving, removing, listing, inspecting resources in state. If you can complete the table above from memory, these are free points.
  2. Backend behavior — what supports locking, what happens at init when the backend changes, why backend blocks can’t contain variables.
  3. What survives state rm — Terraform forgets the resource; the real object is untouched.
  4. Sensitive data — where secrets live, what sensitive = true actually does.
  5. 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:

  1. Initialize a project with a local backend, then migrate it to S3/GCS/Azure with terraform init and watch the migration prompt.
  2. Run terraform state list and state show on a real project until the address format is second nature.
  3. Rename a resource block, run plan, and watch the destroy/recreate. Fix it with terraform state mv, re-plan, and confirm zero changes. Repeat with a moved block.
  4. terraform state rm a resource, confirm it still exists in the cloud, then bring it back with an import block.
  5. Kill a terraform apply mid-run against a locking backend and recover with force-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%.

Limited Time Offer: Get 80% off all Mock Exam Bundles | Sale ends in 7 days. Start learning today.

Claim Now