Terraform Remote State — S3 + DynamoDB
Terraform state file (terraform.tfstate) records real infrastructure. Remote state in AWS S3 prevents local machine dependency and enables team collaboration. DynamoDB state locking prevents two people applying simultaneously. Single source of truth, versioning via S3, lock table with LockID/Status/Info.
Overview
What Terraform state is
Terraform state is a JSON file (terraform.tfstate) that records the real infrastructure Terraform manages. It maps .tf resource definitions to actual cloud resource IDs, attributes and dependencies. Without accurate state, Terraform cannot plan or destroy correctly.
What state tracks
- Resource ID — aws_instance.web → i-0abc12345
- Attributes returned by the cloud API — Public IP, ARN, created_at
- Dependencies between resources — The security group must exist before the EC2 instance
- Metadata — Terraform version, provider versions
Why remote state is required for teams
- Single machine dependency — Only the engineer on that machine can run Terraform; their laptop becomes a single point of failure for all infrastructure operations
- No collaboration — Two engineers cannot work on infrastructure from different machines
- No audit trail — Local state changes are not visible to anyone else, and there is no history
- Race conditions — Two engineers apply at the same time from separate local state files; both see the same pre-apply state, both plan, both apply: duplicate resources, inconsistent state, corruption
The S3 backend
- Centralized, durable, highly available — One copy of state every machine reads
- Server-side encryption (KMS) — State at rest is encrypted
- S3 versioning — Roll back to a previous state version if an apply corrupts it
- IAM policies — Control who can read and write state
Locking
When Terraform starts plan or apply, it writes a lock record. If another operation finds an existing lock, it fails immediately with the lock holder's details. The lock is released when the operation finishes, normally or with an error.
- LockID — Unique identifier
- Status — Current state of the lock
- Info — Who is running, from where
- Created — Timestamp
> [!IMPORTANT] As of Terraform 1.10, use_lockfile = true locks inside S3 itself with a conditional-write .tflock object, and 1.11 deprecated dynamodb_table. The DynamoDB table is the older pattern.
Key concepts
- terraform.tfstate
- JSON file mapping Terraform resource addresses to real cloud resource IDs and attributes. The ground truth for what Terraform currently manages. Corrupted or lost state = Terraform can no longer manage existing resources.
- S3 backend configuration
- terraform { backend "s3" { bucket = "my-org-tf-state"; key = "prod/vpc/terraform.tfstate"; region = "us-east-1"; dynamodb_table = "terraform-lock"; encrypt = true } }. Set key uniquely per environment/resource group to prevent state file collisions.
- DynamoDB lock table
- A DynamoDB table with hash key LockID (String). Terraform creates one record per active operation. The record contains who holds the lock, when it was acquired, and what operation is running. Prevents concurrent applies that would corrupt state.
- terraform_remote_state
- Data source that reads outputs from another Terraform state file in S3. Enables cross-stack references: the networking stack exports vpc_id; the application stack reads it. Decouples stacks while sharing values.
- State encryption
- State files often contain sensitive values (database passwords, private keys). S3 server-side encryption (SSE-KMS) encrypts state at rest. Additionally, Terraform 1.7+ supports provider-level state encryption to encrypt sensitive values within the state file itself.
- State locking danger: stale lock
- If a Terraform operation crashes without releasing the lock, the DynamoDB lock record remains. Subsequent operations fail with "lock held." Fix: terraform force-unlock — use with extreme caution after confirming no operation is running.
When to use it
- Any Terraform project with more than one engineer — remote state is mandatory
- CI/CD pipelines for infrastructure — runners need shared state; local state is destroyed with the runner
- Multiple environments (dev/staging/prod) sharing modules — separate state keys per environment
- Compliance requirements for infrastructure change audit trails
- Cross-stack references — terraform_remote_state data source reads outputs from another state file
Interview questions
- What is Terraform state and why does remote state matter?
- What happens if a Terraform apply crashes mid-run and the DynamoDB lock is not released?
Sign up free to read the full topic
More DevOps topics
- Tekton
- Terraform — Production Errors, Mistakes and Recovery
- Terraform & OpenTofu
- Terraform count vs for_each
- Terraform Essentials — Plan and Apply, Variables, Outputs, Data Sources, and Sharing State at Scale
- Terraform in CI/CD Pipelines
- Test Pyramid
- The C/C++ Compilation Model
- The flux CLI
- The Three Ways
- Toil Reduction & Automation Strategy
- Trunk-Based Development
Start free on Cariara · Coding problems · System design studio