Quick Answer
Terraform state tracks every resource you manage. Store it remotely (S3, Azure Blob, GCS) with locking (DynamoDB, native) to enable team collaboration and prevent corruption. Never edit state files manually — use terraform state commands.
What is Terraform State?
The state file (terraform.tfstate) is a JSON file that maps your HCL configuration to real cloud resources:
{
"resources": [{
"type": "aws_instance",
"name": "web",
"instances": [{
"attributes": {
"id": "i-1234567890abcdef0",
"ami": "ami-0abcdef1234567890",
"instance_type": "t3.micro",
"public_ip": "54.123.45.67"
}
}]
}]
}
Without state, Terraform can’t know which cloud resources it created, what to update, or what to destroy.
Local vs Remote State
| Feature | Local (terraform.tfstate) | Remote (S3/Azure/GCS) |
|---|---|---|
| Team access | ❌ Single machine | ✅ Shared |
| Locking | ❌ None | ✅ DynamoDB/native |
| Encryption | ❌ Plaintext | ✅ At rest |
| Versioning | ❌ No history | ✅ Rollback |
| CI/CD | ❌ Needs file sharing | ✅ Native |
| Risk of loss | ❌ Laptop crash = gone | ✅ Cloud durability |
Configure Remote State with Locking
AWS S3 + DynamoDB
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "prod/app/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Azure Blob Storage
terraform {
backend "azurerm" {
resource_group_name = "terraform-rg"
storage_account_name = "tfstatemycompany"
container_name = "tfstate"
key = "prod.terraform.tfstate"
}
}
GCP Cloud Storage
terraform {
backend "gcs" {
bucket = "mycompany-terraform-state"
prefix = "prod/app"
}
}
How State Locking Works
terraform applystarts → requests a lock- Lock acquired → proceeds with changes
- Another user runs
apply→ sees “Error acquiring state lock” → waits - First apply finishes → lock released → second user can proceed
# If a lock gets stuck (crashed process, lost connection):
terraform force-unlock LOCK_ID
# Get LOCK_ID from the error message
Essential State Commands
# List all resources in state
terraform state list
# Show details of one resource
terraform state show aws_instance.web
# Move a resource (rename without destroy/recreate)
terraform state mv aws_instance.web aws_instance.app
# Remove from state (resource stays in cloud, Terraform forgets it)
terraform state rm aws_instance.web
# Import existing resource into state
terraform import aws_instance.web i-1234567890abcdef0
# Pull remote state to local file (backup)
terraform state pull > backup.tfstate
# Push local state to remote (dangerous — use carefully)
terraform state push backup.tfstate
# Refresh state from cloud (sync drift)
terraform apply -refresh-only
State and Sensitive Data
State files contain everything — including passwords, API keys, and connection strings:
# This is in your state file in plaintext:
# "password": "super-secret-db-password"
Protect state with:
- Encryption at rest (S3 SSE-KMS, Azure encryption, GCS encryption)
- Access control (IAM policies restricting who can read state)
- Never commit to git — add
*.tfstateto.gitignore - Never share state files via email or chat
State File Organization
Split state by environment and component to reduce blast radius:
# One giant state = high risk
prod/everything/terraform.tfstate ← one bad apply affects everything
# Split state = low risk
prod/networking/terraform.tfstate ← VPC, subnets, security groups
prod/database/terraform.tfstate ← RDS, ElastiCache
prod/compute/terraform.tfstate ← EC2, ASG, ALB
prod/dns/terraform.tfstate ← Route53
Common Issues
| Problem | Solution |
|---|---|
| “Error acquiring state lock” | Wait for other apply, or force-unlock |
| State file corrupted | Restore from S3 versioning |
| Drift (cloud ≠ state) | terraform apply -refresh-only |
| Resource in wrong state file | terraform state mv -state-out=other.tfstate |
| Need to see what’s in state | terraform state list then terraform state show |
Best Practices
- Always use remote state for team projects
- Enable versioning on state bucket — your disaster recovery
- Enable encryption — state contains secrets
- Split state by component — smaller blast radius
- Never edit state JSON manually — use
terraform statecommands - Use
prevent_destroyon state storage resources - Run
terraform planbeforeapply— always review changes
Hands-On Courses
Related Articles
- Terraform Remote State with S3
- Terraform Backend Configuration Guide
- Fix State Lock Conflict
- Terraform Glossary
Conclusion
Terraform state is the single source of truth for your infrastructure. Store it remotely with locking and encryption, never edit it manually, split it by component, and treat it like a database — because it is one. Master terraform state commands and you’ll handle any state issue that comes up.




