Terraform State Management

Terraform state is a crucial component that tracks the mapping between your configuration and the real-world infrastructure. Understanding state management is essential for working effectively with Terraform.

What is State?

Purpose of State

Terraform stores state about your managed infrastructure and configuration. This state is used to:

  • Map real-world resources to your configuration
  • Track metadata about resources
  • Improve performance by caching resource information
  • Enable Terraform to determine what needs to be created, updated, or destroyed

Local State (Default)

Local State File

By default, Terraform stores state locally in a file named terraform.tfstate:

# Default local state
# Stored in terraform.tfstate

# View state
terraform show

# List resources in state
terraform state list

# Show specific resource
terraform state show aws_instance.web

# State file structure (JSON)
{
  "version": 4,
  "terraform_version": "1.6.0",
  "resources": [
    {
      "type": "aws_instance",
      "name": "web",
      "instances": [
        {
          "attributes": {
            "id": "i-1234567890abcdef0",
            "ami": "ami-0c55b159cbfafe1f0",
            "instance_type": "t2.micro",
            ...
          }
        }
      ]
    }
  ]
}
⚠️ Warning: Local state files should NOT be committed to version control as they may contain sensitive information. Always use .gitignore to exclude state files.

Remote State Backends

Why Use Remote State?

  • Team Collaboration - Multiple team members can work together
  • State Locking - Prevents concurrent modifications
  • Centralized Storage - Single source of truth
  • Security - State stored securely with encryption
  • Versioning - Keep history of state changes

AWS S3 Backend

terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
    
    # Optional: Versioning
    versioning = true
    
    # Optional: Server-side encryption
    server_side_encryption_configuration {
      rule {
        apply_server_side_encryption_by_default {
          sse_algorithm = "AES256"
        }
      }
    }
  }
}

Azure Storage Backend

terraform {
  backend "azurerm" {
    resource_group_name  = "terraform-state-rg"
    storage_account_name = "terraformstate"
    container_name       = "tfstate"
    key                  = "terraform.tfstate"
  }
}

GCP Cloud Storage Backend

terraform {
  backend "gcs" {
    bucket  = "terraform-state-bucket"
    prefix  = "terraform/state"
    project = "my-gcp-project"
  }
}

Terraform Cloud Backend

terraform {
  cloud {
    organization = "my-org"
    workspaces {
      name = "production"
    }
  }
}

Initializing Remote Backend

# Migrate existing state to remote backend
terraform init -migrate-state

# You'll be prompted to confirm migration
# Type 'yes' to migrate state to the new backend

State Locking

What is State Locking?

State locking prevents concurrent operations from modifying the same state file simultaneously. This ensures consistency and prevents corruption.

S3 + DynamoDB State Locking

# Create DynamoDB table for state locking
resource "aws_dynamodb_table" "terraform_state_lock" {
  name           = "terraform-state-lock"
  billing_mode   = "PAY_PER_REQUEST"
  hash_key       = "LockID"

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

  tags = {
    Name = "Terraform State Lock Table"
  }
}

# Configure backend with DynamoDB
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-state-lock"
    encrypt        = true
  }
}

State Commands

Viewing State

# Show current state in human-readable format
terraform show

# Show state as JSON
terraform show -json

# List all resources in state
terraform state list

# Show specific resource
terraform state show aws_instance.web

# Show resource at path
terraform state show 'module.vpc.aws_vpc.main'

Modifying State

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

# Move resource to different module
terraform state mv aws_instance.web 'module.vpc.aws_instance.web'

# Remove resource from state (doesn't destroy)
terraform state rm aws_instance.web

# Pull current state
terraform state pull > terraform.tfstate.backup

# Push state (use with caution)
terraform state push terraform.tfstate

Importing Resources

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

# Import with resource address
terraform import 'module.vpc.aws_instance.web' i-1234567890abcdef0

# Import with multiple instances
terraform import 'aws_instance.web[0]' i-1234567890abcdef0
terraform import 'aws_instance.web[1]' i-1234567890abcdef1

# Prepare import block (Terraform 1.5+)
import {
  to = aws_instance.web
  id = "i-1234567890abcdef0"
}

# Then run
terraform plan -generate-config-out=generated.tf

State File Structure

Understanding State Format

{
  "version": 4,
  "terraform_version": "1.6.0",
  "serial": 1,
  "lineage": "abc123-def456-...",
  "outputs": {
    "instance_id": {
      "value": "i-1234567890abcdef0",
      "type": "string"
    }
  },
  "resources": [
    {
      "mode": "managed",
      "type": "aws_instance",
      "name": "web",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "ami": "ami-0c55b159cbfafe1f0",
            "id": "i-1234567890abcdef0",
            "instance_type": "t2.micro",
            ...
          },
          "sensitive_attributes": [],
          "private": "..."
        }
      ]
    }
  ]
}

State Backups

Automatic Backups

Terraform automatically creates backup files:

# Local backend creates
terraform.tfstate.backup  # Automatic backup before modifications

# Remote backends (S3, etc.) support versioning
# Enable versioning on S3 bucket for state history

Manual Backups

# Backup current state
terraform state pull > terraform.tfstate.backup

# Restore from backup
terraform state push terraform.tfstate.backup

State Troubleshooting

State Lock Issues

⚠️ Issue: State is locked
Error: Error acquiring the state lock
Lock Info:
  ID:        abc123...
  Path:      my-terraform-state-bucket/terraform.tfstate
  Operation: OperationTypePlan
  Who:       [email protected]
  Version:   1.6.0
  Created:   2024-01-15 10:00:00 +0000 UTC

Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again. For most commands, you can disable locking with the "-lock=false"
flag, but this is not recommended.
Solutions:
  • Wait for the other operation to complete
  • If process crashed, manually unlock: terraform force-unlock <LOCK_ID>
  • Check DynamoDB table (for S3 backend) for stale locks

Force Unlock

# Force unlock state (use with caution)
terraform force-unlock <LOCK_ID>

# Get lock ID from error message

State Drift

💡 State Drift Detection:

If resources are modified outside of Terraform, use terraform refresh to update state with real-world infrastructure.

# Refresh state
terraform refresh

# Refresh specific resource
terraform refresh -target=aws_instance.web

# Plan with refresh
terraform plan -refresh=true

State Corruption

⚠️ If State is Corrupted:
  1. Restore from backup: terraform state push terraform.tfstate.backup
  2. Re-import resources: terraform import <resource> <id>
  3. Recreate state from scratch (last resort)

State Best Practices

✅ Best Practices:
  • ✅ Always use remote state backends in production
  • ✅ Enable state locking to prevent concurrent modifications
  • ✅ Enable encryption for state files (at rest and in transit)
  • ✅ Enable versioning on state storage (S3, GCS)
  • ✅ Use separate state files per environment
  • ✅ Never commit state files to version control
  • ✅ Use .gitignore to exclude state files
  • ✅ Regularly backup state files
  • ✅ Use workspaces or separate directories for environments
  • ✅ Monitor state file size (keep it reasonable)

State File Size Management

Large State Files

# Check state file size
ls -lh terraform.tfstate

# If state file is too large:
# 1. Split into multiple workspaces
# 2. Use modules to organize resources
# 3. Remove unused resources from state

Cleaning Up State

# Remove resources that no longer exist
terraform state list
terraform state rm aws_instance.deleted

# Compact state file (removes unused data)
terraform state rm -dry-run # Test first
terraform state rm <unused_resource>

Workspaces

Using Workspaces for Environments

# Create workspace
terraform workspace new development
terraform workspace new staging
terraform workspace new production

# List workspaces
terraform workspace list

# Select workspace
terraform workspace select production

# Show current workspace
terraform workspace show

# Delete workspace
terraform workspace delete development

Workspace-Specific State

# State files per workspace
terraform.tfstate.d/
  ├── development/
  │   └── terraform.tfstate
  ├── staging/
  │   └── terraform.tfstate
  └── production/
      └── terraform.tfstate
💡 Tip: Use workspaces for managing multiple environments with the same configuration, but different variable values.

Next Steps