# How do I safely manage Terraform state with S3 + DynamoDB locking?

> Move state to a versioned, encrypted S3 backend and add a DynamoDB lock table (deprecated but working), keep state per environment, and apply only from CI.

- Asked: 2026-06-12
- Answered: 2026-06-12
- Asked by: Nadir
- Tags: ci-cd, altyapi
- Source: https://www.muhammetsafak.com.tr/en/just-ask/terraform-remote-state-and-locking-with-s3-and-dynamodb/
- Language: en-US
- Author: Muhammet Şafak

---
**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?


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 was the industry standard for years, but DynamoDB locking has been deprecated since Terraform 1.11.

The root of the issue is a single shared file being written by three people at once, without a lock.

1. **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.
2. **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.
3. **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.
4. **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 state` commands.

**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; the DynamoDB lock table is still widely used, but HashiCorp has deprecated it and plans to remove it — it's still the one the team can adopt without hesitation today. Whether IaC is really worth adopting, or a script is enough, I discuss separately on sade.dev.

## Related Reading

- [How do I set up secretless AWS access in CI/CD with OIDC and IAM roles?](https://www.muhammetsafak.com.tr/en/just-ask/secretless-ci-cd-with-aws-iam-roles-and-oidc/) — Just Ask
- [How do I shrink Docker images with multi-stage builds and distroless?](https://www.muhammetsafak.com.tr/en/just-ask/shrinking-docker-images-with-multi-stage-builds-and-distroless/) — Just Ask
- [How do I set up CDN asset versioning: hashing and a cache strategy on deploy?](https://www.muhammetsafak.com.tr/en/just-ask/cdn-asset-versioning-and-cache-strategy-on-deploy/) — Just Ask
