Quick Answer
Terraform state (terraform.tfstate) tracks the mapping between your config and real infrastructure. Use remote backends (S3, Azure Blob, GCS) with state locking for team collaboration. Never edit state files manually — use terraform state commands.
What Is Terraform State?
Terraform state is a JSON file that records which real-world resources correspond to which resources in your configuration.
# View all resources in state
terraform state list
# View details of a specific resource
terraform state show aws_instance.web
Without state, Terraform can’t know what it’s managing. Every plan and apply reads state to calculate changes.
Local vs Remote State
Local State (Default)
# State stored in current directory
ls terraform.tfstate
Problems with local state:
- Can’t collaborate with a team
- No locking — concurrent runs corrupt state
- No backup — lose the file, lose everything
- Secrets stored in plain text on disk
Remote State with S3 + DynamoDB
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "production/network/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
Create the backend resources:
# In a separate bootstrap config
resource "aws_s3_bucket" "state" {
bucket = "mycompany-terraform-state"
lifecycle {
prevent_destroy = true
}
}
resource "aws_s3_bucket_versioning" "state" {
bucket = aws_s3_bucket.state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_dynamodb_table" "locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
State Commands
terraform state list
# List all resources
terraform state list
# Filter with grep
terraform state list | grep aws_instance
terraform state show
# Inspect a resource's attributes
terraform state show aws_instance.web
terraform state mv
# Rename a resource (no destroy/recreate)
terraform state mv aws_instance.web aws_instance.app
# Move into a module
terraform state mv aws_instance.web module.compute.aws_instance.web
terraform state rm
# Remove from state WITHOUT destroying the real resource
terraform state rm aws_instance.web
# Now Terraform no longer manages this instance
terraform state pull / push
# Download remote state to inspect
terraform state pull > state.json
# Restore state (DANGEROUS — use with caution)
terraform state push state.json
State Locking
State locking prevents two users from applying at the same time:
User A: terraform apply → acquires lock ✅
User B: terraform apply → "Error: state locked" ❌ (waits)
User A: apply completes → releases lock
User B: terraform apply → acquires lock ✅
If a lock gets stuck (crashed apply):
terraform force-unlock LOCK_ID
Backend Comparison
| Backend | Locking | Encryption | Free Tier |
|---|---|---|---|
| S3 + DynamoDB | ✅ | ✅ | ✅ |
| Azure Blob | ✅ | ✅ | ✅ |
| GCS | ✅ | ✅ | ✅ |
| Terraform Cloud | ✅ | ✅ | Free for 5 users |
| Local | ❌ | ❌ | ✅ |
State File Organization
s3://mycompany-terraform-state/
├── production/
│ ├── network/terraform.tfstate
│ ├── compute/terraform.tfstate
│ └── database/terraform.tfstate
├── staging/
│ ├── network/terraform.tfstate
│ └── compute/terraform.tfstate
└── shared/
└── dns/terraform.tfstate
Troubleshooting
| Problem | Fix |
|---|---|
| State locked | terraform force-unlock LOCK_ID |
| State out of sync | terraform apply -refresh-only |
| Resource not in state | terraform import TYPE.NAME ID |
| Need to rename | terraform state mv OLD NEW |
| Stop managing a resource | terraform state rm TYPE.NAME |
Related Articles
Conclusion
Use remote backends with locking from day one. Organize state files by environment and component. Use terraform state commands for moves and imports — never edit state JSON manually. Enable versioning on your state bucket so you can recover from mistakes.




