DEV Community

Mary Mutua
Mary Mutua

Posted on

Managing Terraform State: Best Practices for DevOps with S3 and DynamoDB

Day 6 of my Terraform journey focused on one of the most important Terraform concepts: state.

Terraform state is the record of what Terraform believes it manages. Every plan, apply, and destroy depends on that state being accurate.

Today I moved from just inspecting local state to setting up remote state storage using Amazon S3 and DynamoDB.

What Terraform State Really Does

Terraform state stores the mapping between:

  • Terraform resources in code
  • the actual infrastructure in AWS

That includes details such as:

  • resource IDs
  • attributes
  • tags
  • outputs
  • provider-managed metadata

This is what allows Terraform to compare code, state, and real infrastructure before deciding what to change.

Why Local State Fails at Scale

Local state works for solo practice, but it breaks down quickly in teams.

Some of the biggest problems are:

  • two people can run Terraform at the same time
  • the state file can be lost if it lives only on one machine
  • state files can contain sensitive data
  • sharing state through Git is unsafe and error-prone

That is why remote state matters.

What a Remote Backend Means

A backend is where Terraform stores its state.

  • if state is stored in terraform.tfstate on your local machine, that is local state
  • if state is stored in a shared service like S3, that is a remote backend

For this lab, I used:

  • S3 to store the state file
  • DynamoDB to provide state locking

My Backend Configuration


terraform {
  backend "s3" {
    bucket         = "mary-mutua-30day-terraform-state-20260325-a1b2"
    key            = "day_6/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-state-locks"
    encrypt        = true
  }
}



Enter fullscreen mode Exit fullscreen mode

What each argument does:

  • bucket - The S3 bucket where Terraform stores the state file
  • key - The path to the state file inside the bucket
  • region - The AWS region where the bucket and locking table exist
  • dynamodb_table - The DynamoDB table Terraform uses for state locking
  • encrypt - Ensures the state file is stored encrypted in S3

Why S3 and DynamoDB Work Well Together

This setup solves several problems at once:

  • S3 gives shared, durable storage for the state file
  • versioning helps recover older versions of state
  • encryption helps protect state at rest
  • DynamoDB locking helps prevent concurrent Terraform operations

That locking behavior matters because two engineers should not be able to update the same state at the same time.

The Bootstrap Problem

One of the most interesting lessons today was the bootstrap problem.

Terraform cannot use an S3 backend until:

  • the S3 bucket already exists
  • the DynamoDB table already exists

So I had to create those resources first in a separate bootstrap configuration.

In simple terms:

  • day_6/bootstrap created the backend infrastructure
  • day_6 used that backend infrastructure

That separation made the whole workflow much easier to understand.

Cleanup Was a Lesson Too

Cleanup was more interesting than I expected.

Because the S3 bucket had:

  • versioning enabled
  • remote state objects inside it

destroying the backend was not as simple as deleting a normal bucket.

I also used prevent_destroy at first as a safety guard so the state bucket could not be removed accidentally. That made it clear that backend infrastructure should be treated more carefully than ordinary lab resources.

Final Thoughts

Day 6 helped me understand that Terraform state is not just an implementation detail. It is the backbone of how Terraform works.

The biggest lessons for me were:

  • local state is fine for learning but weak for teams
  • remote backends make collaboration safer
  • S3 and DynamoDB are a practical Terraform backend pattern on AWS
  • state locking matters
  • backend infrastructure needs special care during cleanup

For the full Terraform files and README notes from this lab, I linked the code here:

👉 Github Link

Follow My Journey

This is Day 6 of my 30-Day Terraform Challenge.

See you on Day 7 🚀

Top comments (0)