Terraform state management and workspace strategies

Ryan Nakamura Feb 2026
2 tabs
# Backend configuration with S3 + DynamoDB locking
terraform {
  backend "s3" {
    bucket         = "company-terraform-state"
    key            = "services/web-app/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-state-locks"
    encrypt        = true
    kms_key_id     = "arn:aws:kms:us-east-1:123456789:key/abcd-1234"

    # Enable versioning on the S3 bucket for state history
  }
}

# DynamoDB table for state locking
resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-state-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }

  tags = {
    Purpose = "Terraform state locking"
  }
}

# S3 bucket for state storage
resource "aws_s3_bucket" "terraform_state" {
  bucket = "company-terraform-state"

  lifecycle {
    prevent_destroy = true
  }
}

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     = "aws:kms"
      kms_master_key_id = aws_kms_key.terraform.id
    }
  }
}

resource "aws_s3_bucket_public_access_block" "terraform_state" {
  bucket                  = aws_s3_bucket.terraform_state.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

# Read outputs from another state (networking)
data "terraform_remote_state" "networking" {
  backend = "s3"
  config = {
    bucket = "company-terraform-state"
    key    = "infrastructure/networking/terraform.tfstate"
    region = "us-east-1"
  }
}

# Use networking outputs
resource "aws_instance" "web" {
  subnet_id = data.terraform_remote_state.networking.outputs.private_subnet_ids[0]
  vpc_security_group_ids = [
    data.terraform_remote_state.networking.outputs.app_security_group_id
  ]
}

# Workspace-aware configuration
locals {
  environment = terraform.workspace

  config = {
    production = {
      instance_type = "t3.large"
      min_size      = 3
      max_size      = 10
      multi_az      = true
    }
    staging = {
      instance_type = "t3.medium"
      min_size      = 1
      max_size      = 3
      multi_az      = false
    }
    development = {
      instance_type = "t3.small"
      min_size      = 1
      max_size      = 1
      multi_az      = false
    }
  }

  env_config = local.config[local.environment]
}

resource "aws_autoscaling_group" "web" {
  min_size         = local.env_config.min_size
  max_size         = local.env_config.max_size
  desired_capacity = local.env_config.min_size
}
2 files · hcl, bash Explain with highlit

Terraform state tracks the mapping between configuration and real infrastructure. Remote state backends like S3, GCS, or Terraform Cloud enable team collaboration. DynamoDB provides state locking to prevent concurrent modifications. The terraform_remote_state data source reads outputs from other state files. State splitting separates concerns—networking, compute, and databases in separate states. Workspaces (terraform workspace) create isolated state per environment from the same configuration. The terraform state mv command refactors resources between states. terraform import brings existing infrastructure under management. State encryption protects sensitive values. terraform state rm removes resources from state without destroying them. Regular state backups prevent data loss.