# 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.

backend "s3"LOCKED
storageAWS S3 (AES-256 Encrypted)
lockingDynamoDB (LockID)
concurrencyMutex Mutually Exclusive
1
Source of Truth
0
Race Conditions
AES256
At-Rest Security
# concept

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.
fatal anti-pattern

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.

# internals

Inside terraform.tfstate

terraform.tfstateRAW JSON STRUCTURE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
{
  "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 number

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

Lineage UUID

Unique project identifier ensuring you never accidentally apply state from one Terraform project over an entirely different project's state.

# production standard

Setting Up AWS S3 Remote Backend with DynamoDB Locking

backend.tfS3 BACKEND CONFIG
1 2 3 4 5 6 7 8 9 10 11
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 LockID of type String.
terminalMIGRATING LOCAL STATE TO REMOTE S3
1 2 3 4 5
# 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.
# concurrency

How DynamoDB State Locking Works

Developer A / CI/CD
Runs terraform apply
Acquires Lock in DynamoDB
Writes LockID entry
Developer B attempts Apply
Denied: "State is locked"
Apply Finishes
Releases LockID
# operations

Essential State CLI Commands

terminalCOMMAND EXAMPLES
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# 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
refactoring

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.

delinking

terraform state rm

Removes the resource from Terraform's management without deleting the actual cloud resource in AWS.

# governance

State Security & Disaster Recovery

Best PracticeWhy It Matters
Enable S3 Bucket VersioningAllows instant restoration if a corrupted state file is uploaded or an accidental destroy occurs.
Strict IAM Least PrivilegeOnly 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 .gitignorePrevents accidental commits of local state test files.