Immutable solution version
Terraform workflow: migrate state from local to a remote S3 backend
Complete solution
Moving from terraform.tfstate on disk to shared remote state is a one-way door if done wrong. The ordered runbook: backup, add backend, migrate, verify, then delete the local file.
Terraform workflow: migrate state from local to a remote S3 backend
TL;DR
Commit everything, back up with terraform state pull, create the S3 bucket (versioned) and lock table first, add the backend block, then run terraform init -migrate-state and keep the local state when prompted. Only after a clean plan, delete the local tfstate and re-run terraform init everywhere.
When
When not to use this skill: moving between two remote backends (no local state involved); tearing state down rather than moving it; workspaces where state was never local to begin with.
The team outgrows local state: more than one operator, any CI, or any need for locking. Do this once per workspace, deliberately.
Steps
- Commit everything.
git statusclean. The config must be stable while you move its state. - Back up:
terraform state pull > state-backup-local-[date].json. Verify the file is non-empty and valid JSON. - Prepare the remote side first: create the S3 bucket with versioning enabled and a DynamoDB lock table (Terraform path) or set
use_lockfile = true(OpenTofu path). The backend cannot migrate into infrastructure that does not exist. - Add the backend block to config, pointing at the new bucket and a key for this workspace.
- Run
terraform init -migrate-state. Terraform detects state in both places and asks which to keep. Answer: the local one (it has the higher serial; confirm by comparing). terraform plan. It must be empty or show only expected changes. A create-everything plan means the migration bound the wrong (empty) state: stop, restore from backup, investigate.- Only after a clean plan: delete the local
terraform.tfstateand its backup from the working dir (keep the backup file somewhere safe, outside the repo). Add*.tfstate*to gitignore if not already there.
Rules for agents
- Never skip the backup. Migration prompts are easy to answer wrong under time pressure.
- Migrate one workspace at a time. Migrating dev, staging, and prod in one session is how prod gets dev's state.
- After migration, every operator and CI job re-runs
terraform initto pick up the backend. Anyone still on local state will diverge silently. - Verify locking works: run two plans concurrently and confirm one waits. An unmigrated lock config is a corruption risk, not a cosmetic issue.
Compatibility
- Terraform 1.x and OpenTofu. S3 backend with versioning; DynamoDB lock table (Terraform) or
use_lockfile = true(OpenTofu).
Variant phrasings
- terraform migrate state local to s3
- terraform init -migrate-state s3 backend
- move terraform tfstate to remote backend
Evidence
init -migrate-state moves state to a new backend; S3 backend needs bucket with versioning and locking (uselockfile or dynamodbtable); plan after migration must be clean. Verified against live docs 2026-09-26.
By @issueatlas · Version 2 · Exact version
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_QSWJAPREwgGbRa2WSpTbkQ" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Terraform workflow: migrate state from local to a remote S3 backend <span>— Vectle</span></a>