6.2.1. Why Locking Matters
💡 First Principle: A lock turns a race condition into a queue — the second operation waits instead of corrupting state — so the value of locking is precisely the corruption it prevents during concurrent apply/destroy runs.
Terraform automatically attempts to lock state before any operation that could write to it (apply, destroy, state mutations) and releases the lock when done. If another operation holds the lock, Terraform waits or errors rather than proceeding — this is what stops two engineers (or two CI jobs) from writing conflicting state simultaneously.
If a process crashes mid-operation, a lock can be left dangling. terraform force-unlock <LOCK_ID> manually releases it — used carefully, only when you're sure no operation is actually running. The -lock=false flag disables locking entirely and is dangerous. By contrast, -lock-timeout=<duration> (e.g. -lock-timeout=60s) leaves locking on and only sets how long Terraform keeps retrying a held lock before erroring (default 0s). Locking only happens on backends that support it (see 6.2.2).
State also carries its own version metadata: a serial number that increases each time the state changes and a lineage ID fixed when that state was first created. Terraform uses them to refuse writing an older or unrelated state over a newer one — for example, terraform state push rejects a state whose lineage differs or whose serial is behind the destination's, unless forced.
⚠️ Exam Trap: force-unlock is for stuck locks, not routine use, and -lock=false should essentially never be used in team settings. The exam may frame a "lock stuck after a crash" scenario — the answer is terraform force-unlock, not deleting state.
Reflection Question: Why is disabling locking with -lock=false far riskier on a remote shared backend than on a single-user local setup?