Skip to content

Latest commit

 

History

History
193 lines (132 loc) · 4.51 KB

File metadata and controls

193 lines (132 loc) · 4.51 KB

Diagnosis - Terraform State Migration

Last Updated: 2026-02-06 by Keming He

Platform

Important

Platform-agnostic - Terraform CLI works identically on macOS, Linux, and Windows.

Diagnose and execute state migrations when refactoring Terraform projects.

Table of Contents

When Migration Is Needed

State addresses follow this format:

module.<instance_name>.resource_type.resource_name[key]
Change Migration Required
Rename module "old" to module "new" Yes
Rename resource "type" "old" to "new" Yes
Change for_each keys Yes
Change module source path No
Rename variables No
Change resource attributes No

Rule: If the state address changes, migration is required.

↑ Back to Table of Contents


Diagnose with Terraform Plan

terraform plan
Plan Output Meaning
~ update in-place Safe - no migration needed
-/+ destroy and create Stop - migration needed

If you see destroy/create for resources you want to keep, perform state migration before applying.

↑ Back to Table of Contents


Migration Strategies

Strategy 1: State Move

Best for simple renames.

# Backup first
terraform state pull > backup.tfstate

# Move resource
terraform state mv 'module.old.aws_vpc.main' 'module.new.aws_vpc.main'

# Move entire module
terraform state mv 'module.old' 'module.new'

# Verify
terraform plan                    # Should show no changes

Strategy 2: Moved Block (Terraform 1.1+)

Best for team coordination and version-controlled migrations.

moved {
  from = module.old
  to   = module.new
}

Terraform handles migration automatically on next apply.

Strategy 3: Import After Remove

Best for complex restructuring.

# Backup
terraform state pull > backup.tfstate

# Remove from state (infrastructure unchanged)
terraform state rm 'aws_s3_bucket.old'

# Update code, then import
terraform import 'aws_s3_bucket.new["key"]' bucket-id

# Verify
terraform plan

↑ Back to Table of Contents


Examples

Module Rename

# module.legacy_vpc -> module.vpc
terraform state mv 'module.legacy_vpc' 'module.vpc'

Resource Rename

# aws_vpc.main_vpc -> aws_vpc.network
terraform state mv 'module.vpc.aws_vpc.main_vpc' 'module.vpc.aws_vpc.network'

Convert to for_each

# Individual resources -> for_each loop
terraform state rm 'aws_s3_bucket.data_dev'
terraform state rm 'aws_s3_bucket.data_prod'

# After updating code
terraform import 'aws_s3_bucket.data["dev"]' data-dev
terraform import 'aws_s3_bucket.data["prod"]' data-prod

↑ Back to Table of Contents


Best Practices

Before:

  • Backup: terraform state pull > backup.tfstate
  • Document: terraform state list > current.txt
  • Test in non-production first

During:

  • One resource at a time
  • Verify after each move: terraform plan should show no changes

After:

  • Confirm: terraform plan shows no unexpected changes
  • Backup final state

Strategy Selection:

Situation Use
Simple rename state mv
Team refactoring moved block
Complex restructuring Import after remove

↑ Back to Table of Contents


References