Terraform State: Remote Backends and Locking
The state file is Terraform's memory: which real resources belong to which blocks in your code. For a team, it must be shared, locked during changes and protected, because it can contain secrets.
An S3 backend with locking
terraform {
backend "s3" {
bucket = "acme-terraform-state"
key = "shop/prod/terraform.tfstate"
region = "ap-south-1"
encrypt = true
use_lockfile = true # S3-native locking (older setups used a DynamoDB table)
}
}
terraform init -migrate-state # move existing local state into the backend
Enable versioning on the state bucket so you can recover an earlier version, and restrict who can read it.
Why locking matters
If two people run apply at the same time against the same state, the second can overwrite the first's changes. With locking, the second run waits or fails with a clear message.
Other backends
- Google Cloud Storage (
gcs) and Azure Storage (azurerm) have built-in locking. - HCP Terraform / Terraform Enterprise and other platforms store state and run plans for you.
Useful state commands
terraform state list # everything Terraform manages
terraform state show aws_s3_bucket.assets # details of one resource
terraform state rm aws_s3_bucket.legacy # stop managing (doesn't delete the bucket)
terraform force-unlock <LOCK_ID> # only if a crashed run left a stale lock
For renames and moves, prefer moved blocks in code over terraform state mv: they're reviewed in pull requests and applied consistently.
Split state sensibly
- One state per environment (dev, staging, prod) so a mistake in dev can't touch prod.
- Separate long-lived foundations (networking, DNS) from frequently changed apps.
- Smaller states mean faster plans and a smaller blast radius.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.