From terraform-iac
Safe procedure for Terraform state manipulation — covers import, mv, rm, and state-split operations with pre/post verification steps and the rollback strategy for each operation.
How this skill is triggered — by the user, by Claude, or both
Slash command
/terraform-iac:state-surgeryThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Terraform's desired state diverges from actual infrastructure — resources exist but aren't in state (need import), resources moved to a refactored module (need `state mv`), resources need to be removed from management without destroying them (need `state rm`), or a monolithic state needs to be split into smaller backends.
Terraform's desired state diverges from actual infrastructure — resources exist but aren't in state (need import), resources moved to a refactored module (need state mv), resources need to be removed from management without destroying them (need state rm), or a monolithic state needs to be split into smaller backends.
Never run state surgery on a shared remote backend without first:
apply is in progress (the lock will prevent it, but check).--dry-run equivalent first where available.# 1. Backup current state
terraform state pull > state-backup-$(date +%Y%m%d-%H%M%S).tfstate
# 2. Verify the backup is valid JSON
python3 -m json.tool state-backup-*.tfstate > /dev/null && echo "Valid"
# 3. List current resources (baseline)
terraform state list > before.txt
# 4. Confirm no in-progress apply
# (Check your backend — S3: check the DynamoDB lock table; Azure: check the blob lease)
Use when: infrastructure exists in the cloud but is not tracked in state.
# 1. Write the resource block in your .tf files first (Terraform won't import without it)
# 2. Dry run: check what will be imported
terraform plan -generate-config-out=generated.tf # TF 1.5+ only
# 3. Import
terraform import aws_s3_bucket.my_bucket my-bucket-name
# 4. Verify: plan should show no changes
terraform plan
# Expected output: "No changes. Your infrastructure matches the configuration."
# If the plan shows changes, the .tf config doesn't match the real resource — reconcile before proceeding.
Mass import: for many resources, write a script that calls terraform import per resource, but verify each one individually before moving to the next.
Use when: renaming a resource, moving it into a module, or moving it between modules. The physical cloud resource does not change.
# Before TF 1.1: use terraform state mv
terraform state mv aws_s3_bucket.old_name aws_s3_bucket.new_name
terraform state mv aws_instance.app module.compute.aws_instance.app
# TF 1.1+: prefer the moved {} block in .tf (tracked in source control, reviewable in PR)
# In your .tf file:
moved {
from = aws_s3_bucket.old_name
to = aws_s3_bucket.new_name
}
Prefer moved {} blocks — they appear in terraform plan output, are reviewed in a PR, and are self-documenting. terraform state mv is for one-off migrations not suitable for the config.
After the move:
terraform plan # Must show: 0 to add, 0 to change, 0 to destroy
Use when: transferring management to another state file, or abandoning Terraform management of a resource that should continue to exist.
terraform state rm aws_s3_bucket.legacy_bucket
# Verify it's gone from state
terraform state list | grep legacy_bucket # should return nothing
After state rm, the resource still exists in the cloud. If you run terraform apply with the resource still in your config, Terraform will try to create a new one (and likely conflict). Remove the resource block from your config at the same time.
Use when: a single state file has grown to cover too many environments or components.
Plan:
old-state: [vpc, eks-cluster, rds, app-1, app-2]
new-state-infra: [vpc, eks-cluster, rds]
new-state-app: [app-1, app-2]
Procedure:
terraform state pull > old.tfstate.new-state-infra:
terraform state mv -state=old.tfstate -state-out=infra.tfstate aws_vpc.main aws_vpc.main
terraform state list -state=infra.tfstate.terraform state push -force infra.tfstate # after switching backend config
# After any state operation
terraform state list > after.txt
diff before.txt after.txt # verify only intended changes
terraform plan
# Must show: "No changes" for unaffected resources
# Any unexpected diff = investigate before applying
| Operation | Rollback |
|---|---|
| Import | terraform state rm <address> |
| State mv | terraform state mv in reverse, or restore backup |
| State rm | terraform import to re-add the resource |
| State split | Restore from backup state; re-push to original backend |
For any operation that produces an unexpected plan, restore from backup:
terraform state push state-backup-<timestamp>.tfstate
terraform state mv when a moved {} block would work — the moved {} block is reviewable, the CLI command is not.state rm without removing the resource block from config — the next plan tries to create a duplicate..tf config exactly — the post-import plan will show unexpected changes; applying those can mutate the real resource.../../agents/iac-policy-and-state-engineer.md — state backend safety and drift detection../../agents/iac-architect.md — state isolation by blast radiusnpx claudepluginhub mcorbett51090/ravenclaude --plugin terraform-iacGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.