Table of Contents

Introduction

Migrating Terraform state between backends is a common operation as teams evolve their infrastructure management practices. Whether moving from local state to S3, or from S3 to Terraform Cloud, this guide covers the process safely.

Prerequisites

  • Terraform installed (v1.0+)
  • Access to both source and destination backends
  • No pending changes (terraform plan shows no changes)
  • Backup of current state

Migration 1 - Local to S3

Step 1 - Backup Current State

cp terraform.tfstate terraform.tfstate.backup

Step 2 - Create S3 Backend Resources

resource "aws_s3_bucket" "terraform_state" {
  bucket = "my-terraform-state-bucket"

  lifecycle {
    prevent_destroy = true
  }
}

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

resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

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

Step 3 - Add Backend Configuration

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

Step 4 - Initialize with Migration

terraform init -migrate-state

Terraform will ask:

Do you want to copy existing state to the new backend?
  Enter a value: yes

Step 5 - Verify

terraform plan
# Should show: No changes. Your infrastructure matches the configuration.

Migration 2 - S3 to Terraform Cloud

Step 1 - Create Terraform Cloud Workspace

Configure your Terraform Cloud organization and workspace.

Step 2 - Update Backend

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

Step 3 - Migrate

terraform init -migrate-state

Migration 3 - Cross-Account S3

Step 1 - Pull State

terraform state pull > state.json

Step 2 - Update Backend Config

terraform {
  backend "s3" {
    bucket         = "new-account-state-bucket"
    key            = "production/terraform.tfstate"
    region         = "us-east-1"
    role_arn       = "arn:aws:iam::ACCOUNT_ID::role/TerraformStateAccess"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

Step 3 - Initialize and Migrate

terraform init -migrate-state

Safety Checklist

Before any migration:

  • Run terraform plan — confirm no pending changes
  • Backup state file locally
  • Ensure new backend is accessible
  • Test with a non-production workspace first
  • Verify state after migration with terraform plan
  • Remove old state from source after confirming

Common Errors

Backend configuration changed

Error: Backend configuration changed

Run terraform init -reconfigure to reinitialize with the new backend.

State lock error during migration

terraform force-unlock LOCK_ID

Hands-On Courses

Conclusion

State migration is straightforward when done carefully. Always backup first, verify after, and test with non-production environments. The terraform init -migrate-state command handles most scenarios automatically.