# terraform / state / remote-backend
The Single Source of Truth: State & S3 Backend
Terraform state (terraform.tfstate) maps your declarative configuration to the actual resources in your cloud provider. For teams and automated CI/CD pipelines, storing state securely on a remote backend like AWS S3 with DynamoDB distributed locking is non-negotiable.
Why Terraform Requires a State File
When you declare resource "aws_instance" "web", AWS returns an instance ID like i-0a1b2c3d4e5f67890. The next time you run terraform apply, Terraform needs to know whether to update the existing instance or create a brand new one. State provides that essential mapping.
4 Core Jobs of the State File
- Resource Mapping: Maps HCL identifiers to cloud API IDs.
- Metadata Tracking: Tracks resource dependencies to calculate parallel execution order.
- Performance Caching: Stores known attributes to minimize expensive API round-trips.
- Sync & Drift Detection: Compares current code vs real cloud state to generate execution plans.
Never Commit State to Git
1. State files contain plain-text passwords and sensitive attributes.
2. Two engineers committing conflicting state files creates catastrophic Git merge conflicts.
3. Git lacks write-locks during active applies.
Inside terraform.tfstate
{
"version": 4,
"terraform_version": "1.6.0",
"serial": 14,
"lineage": "c498321a-9812-40ae-bf71-098246a781b2",
"resources": [
{
"mode": "managed",
"type": "aws_instance",
"name": "web",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"attributes": {
"id": "i-0a1b2c3d4e5f67890",
"ami": "ami-0123456789abcdef0",
"public_ip": "13.235.45.109"
}
}
]
}
]
}
Serial Counter
Every time state is modified, Terraform increments the serial number. If two developers try to write conflicting state versions, Terraform detects the serial mismatch and prevents corruption.
Lineage UUID
Unique project identifier ensuring you never accidentally apply state from one Terraform project over an entirely different project's state.
Setting Up AWS S3 Remote Backend with DynamoDB Locking
terraform { backend "s3" { bucket = "shan-tfstate-ap-south-1" key = "prod/app-stack/terraform.tfstate" region = "ap-south-1" dynamodb_table = "terraform-state-locks" encrypt = true } }
Prerequisites to Create in AWS
- S3 Bucket: Must have Versioning Enabled so you can roll back corrupted state, and SSE-S3 / KMS Encryption.
- DynamoDB Table: Must be created with a primary partition key named
LockIDof type String.
# Run init to migrate existing local state to the newly configured S3 bucket $ terraform init -migrate-state Do you want to copy existing state to the new backend? Enter a value: yes Successfully configured the backend "s3"! Terraform will now use this backend.
How DynamoDB State Locking Works
Runs
terraform applyWrites LockID entry
Denied: "State is locked"
Releases LockID
Essential State CLI Commands
# 1. List all managed resources in state $ terraform state list aws_instance.web aws_s3_bucket.app_data # 2. Show full attributes of a resource $ terraform state show aws_instance.web # 3. Rename a resource without destroying it $ terraform state mv aws_instance.web aws_instance.app_server # 4. Remove a resource from state (keep alive in AWS) $ terraform state rm aws_s3_bucket.app_data
terraform state mv
If you rename a block from resource "aws_instance" "web" to resource "aws_instance" "app", Terraform normally destroys and recreates it. Using state mv updates the state index without deleting the live server.
terraform state rm
Removes the resource from Terraform's management without deleting the actual cloud resource in AWS.
State Security & Disaster Recovery
| Best Practice | Why It Matters |
|---|---|
| Enable S3 Bucket Versioning | Allows instant restoration if a corrupted state file is uploaded or an accidental destroy occurs. |
| Strict IAM Least Privilege | Only CI/CD execution roles and Senior DevOps engineers should have write access to the state bucket. |
| Enable Server-Side Encryption (SSE-KMS) | Protects database passwords, TLS private keys, and user-data secrets stored inside the state file. |
Add *.tfstate to .gitignore | Prevents accidental commits of local state test files. |