Skip to content

Operations

Scope

State management, workspace patterns, CI/CD integration, drift detection, and operational best practices.

State Management

Backend Configuration

Backend State Locking Encryption Team Use Cost
S3 + DynamoDB Yes SSE-S3/KMS Multi-user Low
GCS Yes (native) Yes Multi-user Low
Azure Blob Yes (lease) Yes Multi-user Low
Terraform Cloud Yes Yes Enterprise Free-$$
Consul Yes Optional Self-hosted Free
Local No No Single user Free
# Production S3 backend
terraform {
  backend "s3" {
    bucket         = "company-terraform-state"
    key            = "prod/network/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    kms_key_id     = "alias/terraform-state"
    dynamodb_table = "terraform-lock"
  }
}

State Operations

# Import existing resource
terraform import aws_instance.web i-1234567890abcdef0

# Move resource in state
terraform state mv aws_instance.old aws_instance.new

# Remove from state without destroying
terraform state rm aws_instance.decommissioned

# List all resources
terraform state list

# Show specific resource
terraform state show aws_instance.web

Workspace Patterns

Environment Isolation

# Per-environment workspaces
terraform workspace new staging
terraform workspace new production
terraform workspace select production

# Use workspace in configs
locals {
  env = terraform.workspace
  instance_type = {
    staging    = "t3.small"
    production = "t3.xlarge"
  }
}

Workspace vs Directory

For significantly different environments, use separate directories with shared modules instead of workspaces. Workspaces share the same backend config and variable structure.

CI/CD Integration

GitHub Actions Pattern

- name: Terraform Plan
  run: |
    terraform init -backend-config=backend.hcl
    terraform plan -out=tfplan -input=false
    terraform show -json tfplan > plan.json

- name: Terraform Apply
  if: github.ref == 'refs/heads/main'
  run: terraform apply -auto-approve tfplan

Drift Detection

# Detect drift without applying
terraform plan -detailed-exitcode
# Exit code: 0 = no changes, 1 = error, 2 = changes detected

Performance Optimization

Strategy Impact When to Use
parallelism flag Faster apply Large infra (default: 10)
-refresh=false Skip state refresh When you know state is current
-target flag Apply specific resources Emergency fixes (avoid in CI)
Module splitting Reduce blast radius 50+ resources per state
Provider caching Faster init CI/CD pipelines

Common Issues

Issue Root Cause Resolution
State lock stuck Crashed apply terraform force-unlock <ID>
Provider version conflict Loose constraints Pin provider versions exactly
Cycle detected Circular dependencies Use depends_on or restructure
State drift Manual changes terraform refresh then fix
Slow plan Large state file Split into smaller states

Commands & Recipes

Core Workflow

# Initialize (download providers)
terraform init

# Preview changes
terraform plan -out=plan.tfplan

# Apply changes
terraform apply plan.tfplan

# Destroy all resources
terraform destroy

# Format and validate
terraform fmt -recursive
terraform validate

State Management

# List resources in state
terraform state list

# Show specific resource
terraform state show aws_instance.web

# Move resource (rename)
terraform state mv aws_instance.old aws_instance.new

# Remove from state (without destroying)
terraform state rm aws_instance.orphan

# Import existing resource
terraform import aws_instance.web i-1234567890abcdef0

# Force unlock (emergency)
terraform force-unlock <LOCK_ID>

Module Pattern

# modules/vpc/main.tf
variable "cidr" {
  type    = string
  default = "10.0.0.0/16"
}

resource "aws_vpc" "main" {
  cidr_block           = var.cidr
  enable_dns_hostnames = true
  tags = { Name = var.name }
}

output "vpc_id" {
  value = aws_vpc.main.id
}

# Root module usage
module "vpc" {
  source = "./modules/vpc"
  cidr   = "10.0.0.0/16"
  name   = "production"
}

Remote Backend (S3)

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

Workspaces

terraform workspace new staging
terraform workspace select staging
terraform workspace list

Sources