BlogIaC

Terraform remote state and locking on S3 and DynamoDB

Move Terraform state off your laptop into an encrypted S3 or GCS backend with locking, so two applies never race and corrupt your infrastructure.

May 5, 2026·9 min readIntermediate

Terraform's default is a terraform.tfstate file on your laptop. It holds every resource id — often secrets in plaintext — and has no locking, so two people running apply at once can corrupt it. Remote state fixes all three problems at once.

Configure an S3 backend

backend.tf
terraform {
backend "s3" {
bucket = "acme-tfstate"
key = "prod/network/terraform.tfstate"
region = "eu-west-1"
dynamodb_table = "tf-locks"
encrypt = true
}
}
Local vs remote state
Local
on one laptop
no locking
secrets in plaintext
lost with the disk
Remote (S3 + DDB)
shared + versioned
DynamoDB lock
SSE encryption
survives, auditable

Locking with DynamoDB

The dynamodb_table gives you a distributed lock. When someone is applying, everyone else waits instead of racing.

bash
aws dynamodb create-table \
--table-name tf-locks \
--attribute-definitions AttributeName=LockID,AttributeType=S \
--key-schema AttributeName=LockID,KeyType=HASH \
--billing-mode PAY_PER_REQUEST
State is a secret
Restrict the bucket to the CI role and your team, enable versioning (so a bad apply is recoverable), and never commit state to Git.

Migrate existing state

bash — one-time migrationlive
terraform init -migrate-state
Initializing the backend...
Do you want to copy existing state to the new backend?
Successfully configured the backend "s3"!
Go deeper in a courseTerraformFrom first resource to CI/CD, the industry-standard IaC tool.View course

Related posts