TFLAB25-Local vs Remote State: Where Does Terraform Store State

Local vs Remote State: Where Does Terraform Store State?

🔧 Terraform Core ⭐ Intermediate terraform.tfstate backend "s3" State Migration encrypt

Scenario

You've been running Terraform from your laptop with the state file stored locally. Your teammate wants to make changes but doesn't have your state file. You need to move state to a shared remote location (S3) so the whole team can collaborate — and understand the difference between local and remote state.

Your Objectives
  • Create a resource with local state (default) and examine the terraform.tfstate file.
  • Add a backend "s3" block and run terraform init to migrate state to S3.
  • Observe that terraform.tfstate is now empty/removed locally.
  • Understand encrypt = true for state-at-rest encryption.

Additional Context

Local state (terraform.tfstate) is a JSON file on disk. It contains every resource Terraform manages, including attribute values. It may contain sensitive data (passwords, keys) in plain text. Sharing it via Git is dangerous and should never be done.

Remote state solves team collaboration by storing state in a shared location (S3, GCS, Azure Blob, HCP Terraform). It also enables state locking (next lab) and encryption at rest. The backend block is configured inside the terraform {} block.

Step 1: Start with local state

# versions.tf — NO backend block → local state by default

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }
  # No backend block → state stored in ./terraform.tfstate
}

provider "aws" { region = "us-east-1" }

resource "aws_s3_bucket" "demo" {
  bucket = "state-demo-bucket"
  tags   = { ManagedBy = "terraform" }
}

Step 2: Add S3 backend and migrate

# versions.tf — AFTER adding backend block

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = { source = "hashicorp/aws", version = "~> 5.0" }
  }

  # S3 backend — state stored remotely
  backend "s3" {
    bucket  = "my-terraform-state-bucket"       # must exist already
    key     = "demo/terraform.tfstate"           # path within the bucket
    region  = "us-east-1"
    encrypt = true                                # encrypt state at rest with AES-256
  }
}

Workflow Commands

# Step 1: Apply with local state
terraform init
terraform apply

# Examine local state
cat terraform.tfstate | head -20
# You'll see JSON with your resource details

# Step 2: Add the backend "s3" block to versions.tf, then:
terraform init
# Terraform asks: "Do you want to copy existing state to the new backend?"
# Type: yes

# Verify: local state file is now almost empty
cat terraform.tfstate
# {"version":4,"terraform_version":"...","serial":0,...,"resources":[]}

# State is now in S3
aws s3 ls s3://my-terraform-state-bucket/demo/

# You can pull remote state locally for inspection
terraform state pull > local-copy.tfstate

terraform destroy
✓ State Migration Output
Initializing the backend...
Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local"
  backend to the newly configured "s3" backend.

  Enter a value: yes

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.