State is Terraform’s record of what it manages. On a team it must be shared and locked.
terraform {
backend "s3" {
bucket = "acme-tfstate-111122223333"
key = "shop/dev/terraform.tfstate"
region = "ap-south-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Create the bucket (versioning on, public access blocked) and a DynamoDB table with the partition key LockID of type String, before the first terraform init.
aws dynamodb create-table --table-name terraform-locks \
--attribute-definitions AttributeName=LockID,AttributeType=S \
--key-schema AttributeName=LockID,KeyType=HASH \
--billing-mode PAY_PER_REQUEST --region ap-south-1
Use a different key per environment and component to keep the blast radius small. Grant access to the state bucket narrowly, since state may hold passwords. If a run is killed and leaves a lock, release it with terraform force-unlock <ID> only after confirming nobody else is applying.