Managing Multiple AWS Accounts with Terraform
Master multi-account AWS management with Terraform. Learn provider aliases, cross-account IAM roles, AWS Organizations integration, and production-ready.
Cloud Computing
Learn how to implement Terraform state locking with AWS DynamoDB to prevent concurrent modifications and state corruption. Complete setup guide with examples.
When multiple team members or CI/CD pipelines work with Terraform simultaneously, there's a real risk of state file corruption. If two people run terraform apply at the same time, both operations might read the same state, make different changes, and overwrite each other's modifications. The result can be orphaned resources, configuration drift, or even infrastructure outages.
Terraform solves this problem with state locking. When using an S3 backend with DynamoDB, Terraform acquires a lock before any operation that could modify the state file. If another process attempts to modify the state while it's locked, Terraform will display an error and wait or exit, preventing corruption.
The locking mechanism follows a simple but effective pattern:
plan, apply, destroy), Terraform writes a lock record to DynamoDBThis mechanism ensures that only one Terraform operation can modify the state at any given time, regardless of whether the operations originate from different machines, users, or CI/CD pipelines.
# state-infrastructure/main.tf
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "terraform_state" {
bucket = "my-company-terraform-state"
lifecycle {
prevent_destroy = true
}
tags = {
Name = "Terraform State"
Environment = "shared"
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
resource "aws_s3_bucket_public_access_block" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-state-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
point_in_time_recovery {
enabled = true
}
tags = {
Name = "Terraform State Locks"
Environment = "shared"
ManagedBy = "terraform"
}
}The LockID attribute is the partition key and must be of type S (String). Terraform uses the state file path as the lock ID, which means each state file gets its own independent lock.
In your main Terraform project, configure the backend:
# backend.tf
terraform {
backend "s3" {
bucket = "my-company-terraform-state"
key = "production/infrastructure/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-locks"
encrypt = true
}
}After adding the backend configuration, initialize Terraform to migrate the state:
terraform initTerraform will detect the backend change and ask if you want to migrate the existing state.
When a lock is active, the DynamoDB table contains a record like this:
{
"LockID": "my-company-terraform-state/production/infrastructure/terraform.tfstate",
"Info": "{\"ID\":\"a1b2c3d4-e5f6-7890\",\"Operation\":\"OperationTypeApply\",\"Info\":\"\",\"Who\":\"user@hostname\",\"Version\":\"1.7.0\",\"Created\":\"2025-01-22T10:30:00.000Z\",\"Path\":\"my-company-terraform-state/production/infrastructure/terraform.tfstate\"}"
}If another user tries to run a Terraform command while the state is locked, they'll see an error like:
Error: Error acquiring the state lock
Error message: ConditionalCheckFailedException: The conditional request failed
Lock Info:
ID: a1b2c3d4-e5f6-7890
Path: my-company-terraform-state/production/infrastructure/terraform.tfstate
Operation: OperationTypeApply
Who: user@hostname
Version: 1.7.0
Created: 2025-01-22 10:30:00.000000 +0000 UTC
Terraform acquires a state lock to protect the state from being
written by multiple users at the same time. Please resolve the
issue above and try again.Sometimes a lock gets stuck — for example, if a CI/CD pipeline crashes mid-apply or a developer's machine loses network connectivity. In these cases, you can force-unlock the state:
terraform force-unlock a1b2c3d4-e5f6-7890⚠️ Warning: Only use force-unlock when you are absolutely certain no other Terraform operation is running. Force-unlocking while another process is actively modifying state will lead to corruption.
Before force-unlocking, verify the lock status in the AWS Console or CLI:
aws dynamodb get-item \
--table-name terraform-state-locks \
--key '{"LockID":{"S":"my-company-terraform-state/production/terraform.tfstate"}}' \
--query 'Item.Info.S' \
--output text | python3 -m json.toolThis shows you who created the lock and when, helping you determine if it's a stale lock or an active operation.
For organizations with multiple environments, use separate state files to enable parallel operations across environments:
# environments/dev/backend.tf
terraform {
backend "s3" {
bucket = "my-company-terraform-state"
key = "dev/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-locks"
encrypt = true
}
}
# environments/prod/backend.tf
terraform {
backend "s3" {
bucket = "my-company-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-locks"
encrypt = true
}
}With this setup, a developer can apply changes to the dev environment while another applies to staging — each has its own lock.
The DynamoDB table uses PAY_PER_REQUEST billing mode, which means you only pay for actual lock operations. Typical Terraform usage generates minimal DynamoDB requests:
For most teams, this costs less than $1 per month — a negligible cost for the protection it provides.
Learn by doing with interactive courses on CopyPasteLearn:
State locking is a non-negotiable requirement for any team using Terraform collaboratively. The S3 + DynamoDB combination provides a reliable, cost-effective, and AWS-native solution that prevents state corruption and ensures safe concurrent operations. Setting it up takes only a few minutes but saves hours of debugging and potential infrastructure issues down the road.
Master multi-account AWS management with Terraform. Learn provider aliases, cross-account IAM roles, AWS Organizations integration, and production-ready.
Learn how to use Terraform data sources to query existing resources, look up AMIs, reference remote state, and build dynamic configurations. Complete.
Learn how to integrate Terraform with GitHub Actions for automated infrastructure deployments. Complete guide with workflows, best practices, and.
Protect your applications with AWS WAF rules managed by Terraform — rate limiting, IP blocking, and SQL injection prevention.