How do I safely manage Terraform state with S3 + DynamoDB locking?
Question
We manage all our AWS infra (VPC, EC2, RDS, S3) with Terraform. There are 3 DevOps engineers on the team; when we change infra at the same time, `terraform.tfstate` can clash and get corrupted. How do I safely store state remotely (S3) and prevent concurrent modifications with DynamoDB state locking?
Answer
Short answer: local terraform.tfstate + 3 people = corruption and race conditions. Move state to a remote backend: S3 for the file, DynamoDB for locking — this combination is the industry’s proven standard.
The root of the issue is a single shared file being written by three people at once, without a lock.
- Put the state file in S3 — versioned, encrypted, IAM-restricted. Turn on bucket versioning so you can roll back from a bad state easily; enable encryption, and limit access to the roles that need it. State is no longer on a laptop but in a central, backed-up place.
- Set up state locking with DynamoDB. Terraform writes a lock row before any apply. When a second person runs apply, the lock is held, so they either wait or fail fast — they don’t overwrite and corrupt the state. The race condition ends right here.
- Keep per-environment state. Don’t share prod, staging, and dev in a single state; give each environment its own state. Otherwise a mistake in staging risks the prod state; separating the blast radius is the cheapest insurance there is.
- Run applies only from CI if you can, and never edit state by hand. A single serialized path (CI) is far safer than parallel applies from three laptops. Don’t touch state manually; if you must fix it, use
terraform statecommands.
Bottom line: I’d go with an S3 (versioned + encrypted) backend + a DynamoDB lock table + per-env state + applies from CI. Note: newer Terraform/OpenTofu can do S3-native locking too, but the DynamoDB lock table is the widely-used, proven setup — the one the team can adopt without hesitation. Whether IaC is really worth adopting, or a script is enough, I discuss separately on sade.dev.
Related Reading
Comments
Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.