Skip to main content

Module 9, Remote State and Team Workflows

Why Remote State

Local state works for solo learning. The moment a second person runs terraform apply, you have a conflict. Remote state stores terraform.tfstate in S3 so the team shares one source of truth. DynamoDB adds locking so only one apply runs at a time.

S3 Backend Configuration

terraform {
backend "s3" {
bucket = "my-company-terraform-state"
key = "finpay/production/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-state-lock"
}
}

Bootstrap, Create the Backend (One Time Only)

# bootstrap/main.tf, run this ONCE manually before everything else
resource "aws_s3_bucket" "terraform_state" {
bucket = "my-company-terraform-state"
}

resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration { status = "Enabled" }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}

resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-state-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute { name = "LockID"; type = "S" }
}
warning

This bootstrap bucket cannot be managed by Terraform itself (chicken-and-egg). Create it manually or with a separate bootstrap workspace.

How Locking Works

1. You run terraform apply
2. Terraform writes a lock record to DynamoDB (LockID = state file path)
3. Colleague tries to apply → Terraform sees the lock → immediately errors
4. Your apply finishes → Terraform deletes the lock
5. Colleague can now apply

If apply crashes with lock stuck:
terraform force-unlock LOCK_ID

State Versioning

S3 versioning on the state bucket means:

  • Every apply creates a new version of terraform.tfstate
  • You can roll back to any previous state if something goes wrong
  • Accidental state file deletion is recoverable
  • Full audit trail of every infrastructure change

This is non-negotiable in production.

Sharing State Between Configs

Use terraform_remote_state to read outputs from another config:

data "terraform_remote_state" "networking" {
backend = "s3"
config = {
bucket = "my-company-terraform-state"
key = "finpay/networking/terraform.tfstate"
region = "us-east-1"
}
}

resource "aws_instance" "app" {
subnet_id = data.terraform_remote_state.networking.outputs.private_subnet_id
}

Knowledge Check

  1. Why is local state insufficient for team use?
  2. What does the DynamoDB table provide in the S3 backend?
  3. What is the bootstrap problem and how do you solve it?
  4. What happens if terraform apply crashes mid-run with a lock in place?
  5. Why should versioning be enabled on the S3 state bucket?
  6. How do you share outputs between two separate Terraform configurations?