Local, Remote, and Locked State

Scenario: Two engineers, unaware of each other, both plan from the same slightly-stale local state file on their own laptops, and both apply - each one now overwrites the other's understanding of what infrastructure actually exists.

The local backend - the default if you configure nothing - simply stores terraform.tfstate as a plain file on whatever disk you're running Terraform from. It's genuinely fine for solo learning and experimentation (which is exactly how the labs in this track work), but it has no concept of concurrent access whatsoever: it cannot stop two people, or two CI runs, from reading and writing it at the same time. A remote backend instead centralizes state in a shared location - commonly with built-in encryption at rest, versioning (so you can recover a previous snapshot), fine-grained access control, and, critically, locking.

Locking is the mechanism that actually prevents the two-engineers scenario above: before writing to state, Terraform first acquires a lock, and any other run attempting a concurrent write is blocked until the lock is released, rather than both writes racing and one silently clobbering the other. Never casually bypass this with -lock=false just to get past an inconvenient wait - that flag exists for narrow recovery scenarios, not routine impatience. Also note that backend configuration is a distinct concept from provider configuration you learned earlier - it governs where state lives, not how Terraform talks to your infrastructure - and changing it requires an explicit, intentional terraform init -migrate-state step, never a silent switch.

Analogy: A remote backend is a shared document vault holding the one master copy of a critical file; locking is the physical checkout card at the vault's front desk. Whoever holds the card is the only one allowed to take the master copy out and bring back a revised version - everyone else has to wait their turn, which is precisely what stops two revisions from being made independently and one silently overwriting the other.

A worked configuration

terraform {
  backend "remote-example" {
    organization = "platform"
    workspace    = "payments-prod"
  }
}
# terraform init -migrate-state

Design your operational runbooks for the day a lock genuinely gets stuck, because it will happen eventually - a CI job crashes mid-apply and never releases its lock. The correct response is to first identify the real holder and check whether that run is actually still active, and only force-unlock using the lock's exact recorded ID once you have real evidence it's stale, never as a reflexive first response to an inconvenient wait. Because state and its backend availability sit directly in your deployment path, monitor the backend itself and make sure it's backed up independently - a remote backend outage blocks every team's deployments at once.

Common mistakes in production

Goal: Force-unlocking a lock that belongs to an actually-active run can let two writers modify state concurrently, which is exactly the corruption locking exists to prevent. A lock simply having existed for a while is not, on its own, proof that it's stale - always verify the holder before forcing it. Reinforce this lesson in the tf-remote-state-locking Terraform lab. Open /labs/terraform and choose slug tf-remote-state-locking; the lab runs real Terraform against the offline FakeCloud provider.