DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • AWS Managed Database Observability: Monitoring DynamoDB, ElastiCache, and Redshift Beyond CloudWatch
  • Cost Is a Distributed Systems Bug
  • Terraform Type Constraints: Best Practices for Enterprise-Scale AWS
  • From Distributed Monolith to Composable Architecture on AWS

Trending

  • Mocking Kafka for Local Spring Development
  • Retesting Best Practices for Agile Teams: A Quick Guide to Bug Fix Verification
  • Observability in Spring Boot 4
  • Securing Everything: Mapping the Right Identity and Access Protocol (OIDC, OAuth2, and SAML) to the Right Identity
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. The Terraform State Locking Migration You Need to Know About: Moving Beyond DynamoDB

The Terraform State Locking Migration You Need to Know About: Moving Beyond DynamoDB

What's happening: HashiCorp is deprecating DynamoDB-based state locking for Terraform's S3 backend. Native S3 locking is the new standard.

By 
kazeem mohammed user avatar
kazeem mohammed
·
Nov. 12, 25 · Analysis
Likes (2)
Comment
Save
Tweet
Share
3.6K Views

Join the DZone community and get the full member experience.

Join For Free

If you've been working with Terraform for a while, you probably have backend configurations that look something like this scattered across your infrastructure repositories. I know I did. And if you're like me, you might have missed a pretty significant announcement from HashiCorp that's going to affect how we handle state locking going forward. 

Let me save you some future headaches: DynamoDB-based state locking is being deprecated.

Yeah, I had the same reaction when I first heard about it. After years of configuring DynamoDB tables for state locks, HashiCorp is phasing it out in favor of native S3 state locking. The good news? The new approach is actually simpler and eliminates an entire AWS resource from your infrastructure stack.

What's Actually Changing?

For years, the standard practice for Terraform state management in AWS looked like this:

Tcl
 
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-prod"
    key            = "network/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-lock-table"
  }
}


We'd create a DynamoDB table specifically for state locking, configure it with the right capacity settings, and reference it in our backend configuration. It worked, but it always felt like an extra piece of infrastructure we had to maintain just to support our infrastructure-as-code tooling.

HashiCorp recognized this friction point and built native locking directly into the S3 backend. The new configuration is cleaner:

Tcl
 
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-prod"
    key            = "network/terraform.tfstate"
    region         = "us-east-1"
    use_lockfile   = true
  }
}


Notice what's missing? No more DynamoDB table reference. The S3 backend now handles locking internally using lock files stored directly in S3. 

Why This Matters for Your Team

This isn't just a cosmetic change. There are real operational benefits to understanding and adopting this new approach:

  • Reduced infrastructure complexity: Every DynamoDB table you provision for state locking is another resource to monitor, pay for, and manage. With native S3 locking, you eliminate that dependency entirely. Fewer moving parts means fewer potential points of failure.
  • Simplified onboarding: When bringing new engineers onto your platform team, you no longer need to explain the DynamoDB component of state management. The mental model becomes simpler: state lives in S3, locks are handled by S3, everything's in one place.
  • Cost optimization: DynamoDB charges for read/write capacity units. Even with on-demand pricing, those costs add up across multiple tables supporting different Terraform projects. S3 locking uses standard S3 API calls, which are generally cheaper at scale.
  • Better alignment with AWS best practices: AWS has been pushing S3 as the centralized data store with increasingly sophisticated features. Native S3 locking leverages these improvements rather than requiring a separate database service.

How to Migrate Your Existing Infrastructure

I recently went through this migration across about 40 different Terraform projects in our organization. Here's the playbook that worked for us:

Step 1: Update Your Backend Configuration

Start with your non-production environments. Update the backend configuration to remove the DynamoDB table reference and add the use_lockfile parameter:

Tcl
 
terraform {
  backend "s3" {
    bucket         = "mycompany-terraform-state-dev"
    key            = "vpc/terraform.tfstate"
    region         = "us-west-2"
    use_lockfile   = true
    encrypt        = true
  }
}


Notice I kept encrypt = true there. Always encrypt your state files. Always.

Step 2: Reinitialize Your Backend

Run terraform init -reconfigure to migrate to the new locking mechanism. This command tells Terraform to reconfigure the backend without trying to migrate state (since the state location itself hasn't changed):

Shell
 
terraform init -reconfigure
```

You'll see output indicating that Terraform is reconfiguring the backend. This operation is safe and doesn't modify your actual infrastructure.

### Step 3: Test the Lock Mechanism

Before rolling this out broadly, verify that locking actually works. Open two terminal windows and try to run `terraform plan` simultaneously in both. The second command should wait with a message about the state being locked:
```
Error: Error acquiring the state lock

Error message: state is locked
Lock Info:
  ID:        abc123-def456-ghi789
  Path:      mycompany-terraform-state-dev/vpc/terraform.tfstate
  Operation: OperationTypePlan
  Who:       your-username@hostname
  Version:   1.6.0
  Created:   2025-11-04 15:23:41.123456789 +0000 UTC


This is what you want to see. It means the locking mechanism is working correctly.

Step 3: Update CI/CD Pipelines

Don't forget about your automation! Your Jenkins, GitLab CI, or GitHub Actions workflows need updating, too. Here's an updated Jenkinsfile stage:

Groovy
 
stage('Terraform Init') {
  steps {
    sh '''
      terraform init \
        -backend-config="bucket=${TF_STATE_BUCKET}" \
        -backend-config="key=${TF_STATE_KEY}" \
        -backend-config="region=${AWS_REGION}" \
        -backend-config="use_lockfile=true"
    '''
  }
}

stage('Terraform Plan') {
  steps {
    sh 'terraform plan -out=tfplan'
  }
}

stage('Terraform Apply') {
  when {
    branch 'main'
  }
  steps {
    input message: "Deploy to production?"
    sh 'terraform apply tfplan'
  }
}


The key here is ensuring your CI system has appropriate IAM permissions to write lock files to S3. More on that in a moment.

The Critical Addition: S3 Bucket Versioning

While we're modernizing our state backend configuration, there's another best practice that deserves attention: S3 bucket versioning.

I learned this lesson the hard way. A few months back, a terraform apply operation failed halfway through due to a network timeout. The state file got corrupted, and we didn't have versioning enabled. Recovering that state involved manually reconstructing resource relationships by cross-referencing AWS Console outputs with our Terraform configurations. It took four hours and a lot of coffee.

Don't be like past me. Enable versioning:

Tcl
 
resource "aws_s3_bucket_versioning" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id

  versioning_configuration {
    status = "Enabled"
  }
}


With versioning enabled, every change to your state file is preserved. If something goes wrong, you can retrieve previous versions directly from the S3 console or AWS CLI: 

Shell
 
aws s3api list-object-versions \
  --bucket my-terraform-state-prod \
  --prefix network/terraform.tfstate


This gives you a complete history of state changes, allowing you to roll back to any previous version if needed. It's like git history for your infrastructure state.

IAM Permissions for the New Locking Mechanism

Your Terraform execution role needs specific S3 permissions to use the native locking functionality. Here's a minimal IAM policy that covers both state management and locking:

JSON
 
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::my-terraform-state-prod/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket",
        "s3:GetBucketVersioning"
      ],
      "Resource": "arn:aws:s3:::my-terraform-state-prod"
    }
  ]
}


Notice that we no longer need any DynamoDB permissions. That's one less policy statement to maintain and audit.

What Happens to Existing DynamoDB Tables?

You might be wondering whether you need to delete your DynamoDB state lock tables immediately. The short answer is: no, but you should plan for it.

After migrating all your Terraform projects to use native S3 locking, your DynamoDB tables will simply stop receiving traffic. They'll sit there, idle, accumulating minimal costs. I recommend keeping them around for a week or two after migration, just in case you need to roll back any configuration changes.

Once you're confident everything is working with the new locking mechanism, you can safely delete these tables. Just make sure you've updated every single Terraform project first. A single forgotten repo that still references the old DynamoDB table will cause mysterious failures when someone tries to use it.

The Bigger Picture

This deprecation is part of a broader pattern in the Terraform ecosystem: simplification and consolidation. HashiCorp has been steadily reducing external dependencies and building more functionality directly into core providers.

We saw something similar with the move toward native Terraform Cloud state management, which eliminates even the S3 dependency. The trend is clear: less infrastructure overhead for infrastructure tooling.

For those of us managing Terraform at scale, these changes are welcome. Each simplification means less cognitive load, fewer potential failure points, and easier onboarding for new team members.

Action Items for Your Team

If you're currently using DynamoDB-based state locking, here's what I recommend:

  1. Audit your Terraform repositories to identify all backend configurations using DynamoDB tables.
  2. Update your documentation to reflect the new recommended approach using native S3 locking.
  3. Enable S3 bucket versioning on all state buckets if you haven't already.
  4. Create a migration plan prioritizing non-production environments first.
  5. Update your CI/CD pipelines to use the new backend configuration.
  6. Schedule the cleanup of DynamoDB tables once the migration is complete.

The migration itself is straightforward, but the planning and coordination across teams takes time. Start early, communicate clearly, and test thoroughly in lower environments.

The future of Terraform state management is simpler, and that's exactly what we need as infrastructure complexity continues to grow everywhere else.

AWS Amazon DynamoDB Terraform (software)

Opinions expressed by DZone contributors are their own.

Related

  • AWS Managed Database Observability: Monitoring DynamoDB, ElastiCache, and Redshift Beyond CloudWatch
  • Cost Is a Distributed Systems Bug
  • Terraform Type Constraints: Best Practices for Enterprise-Scale AWS
  • From Distributed Monolith to Composable Architecture on AWS

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook