# Atmos Terraform State Migrations

> Terraform state migration workflow with tfmigrate in Atmos: writing migration HCL, running atmos terraform migrate plan/apply/list, wiring kind: tfmigrate hooks, configuring history mode, and handling state refactors, rerun safety, workspace context, backend history variables, and CI-safe migrations.

- Skill: `cloudposse/atmos-terraform-state-migrations` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add cloudposse/atmos-terraform-state-migrations`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cloudposse/atmos-terraform-state-migrations/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: cloudposse (https://skillmd.com/u/cloudposse)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cloudposse/atmos-terraform-state-migrations

---


# Atmos Terraform State Migrations

Use this skill when creating or reviewing Terraform state migrations for Atmos components. Atmos delegates state
migrations to `tfmigrate`. It runs `tfmigrate` in the same component context as `atmos terraform plan` and `apply`.
Before `tfmigrate` runs, Atmos performs auth identity setup, source and workdir provisioning, backend and varfile
generation, Terraform init, workspace selection, toolchain resolution, and `TFMIGRATE_EXEC_PATH` setup.

For migration HCL syntax and examples, load
[references/tfmigrate-migration-patterns.md](references/tfmigrate-migration-patterns.md).

## Start With Resolved Context

Never guess stack names, component names, workspaces, backend paths, or state addresses.

```bash
atmos describe component <component> -s <stack>
atmos terraform migrate list <component> -s <stack>
atmos terraform state list <component> -s <stack>
```

Use the resolved component output to confirm:

- the final Terraform component and component path
- Terraform workspace name
- backend type and backend settings
- whether a `kind: tfmigrate` hook already exists
- history key and history bucket from `atmos terraform migrate list`

Use `atmos terraform state show <component> -s <stack> <address>` when resource identity or import IDs are unclear.
If a refactor can be handled with Terraform `moved` blocks and stays in the same state, prefer that unless the user
specifically needs `tfmigrate` automation or multi-state moves.

## One-Off CLI Workflow

Create a migration file in a project-owned migrations directory, then preview it before applying. `tfmigrate`
resolves `--migration` relative to the `migration_dir` in its config. The Atmos-generated default config points
`migration_dir` at the component's `migrations/` directory when one exists. Pass just the filename, not a
`migrations/`-prefixed path.

```bash
atmos terraform migrate plan <component> -s <stack> --migration 20260527090000_refactor_vpc.hcl
atmos terraform migrate apply <component> -s <stack> --migration 20260527090000_refactor_vpc.hcl
```

For multiple selected component instances:

```bash
atmos terraform migrate plan --components vpc,eks -s <stack> --migration 20260527090000_refactor.hcl
atmos terraform migrate plan --query '.settings.requires_migration == true' --tfmigrate-config .tfmigrate.hcl
atmos terraform migrate plan --affected --migration 20260527090000_refactor.hcl
```

Do not run `apply` until `plan` succeeds and the Terraform plan after migration does not show unintended destroy/create
changes. `--affected` does not support `--include-dependents` for migrate.

## Migration Files

Use `tfmigrate` HCL for state operations that need reviewable, repeatable files. A migration file contains exactly one
`migration` block.

```hcl
migration "state" "rename_subnet" {
  actions = [
    "mv aws_subnet.private aws_subnet.private_primary",
  ]
}
```

Common actions:

- `mv <source> <destination>` for renames and module/address moves in one state.
- `rm <addresses>...` for removing state bindings without destroying infrastructure.
- `import <address> <id>` for binding existing infrastructure.
- `replace-provider <from> <to>` for provider address migrations.
- `xmv <source-pattern> <destination-pattern>` for wildcard moves.
- `migration "multi_state"` for moving resources between component directories or state files.

Keep migration filenames sortable, usually with a timestamp prefix. In history mode, unapplied migrations are processed
in filename order.

## Hook Wiring

Use hooks when the migration should run as part of normal `plan`, `apply`, or `deploy` workflows.

```yaml
components:
  terraform:
    s3-bucket:
      dependencies:
        tools:
          tfmigrate: "0.4.x"

      hooks:
        state-migration:
          events:
            - before.terraform.plan
            - before.terraform.apply
          kind: tfmigrate
          migration: 20260527090000_remove_template_provider.hcl
          mode: dynamic
```

`mode: dynamic` is the default. `before.terraform.plan` runs `tfmigrate plan`. `before.terraform.apply` and
`before.terraform.deploy` run `tfmigrate apply`. Use `mode: plan` or `mode: apply` only when the hook must always run
one action.

Hook fields:

- `migration`: path to one migration file.
- `config`: path to `.tfmigrate.hcl`; omit `migration` when using history mode.
- `backend_config`: entries passed as repeated `tfmigrate --backend-config` flags for the Terraform state backend.
- `mode`: `dynamic`, `plan`, or `apply`.

## History Mode

Single-file `tfmigrate apply path.hcl` is not idempotent. A rerun can fail if a source address already moved, or an
address was already removed. For CI-safe reruns, use `tfmigrate` history mode with durable storage.

```yaml
hooks:
  state-migration:
    events:
      - before.terraform.plan
      - before.terraform.apply
    kind: tfmigrate
    config: .tfmigrate.hcl
    mode: dynamic
```

Atmos exposes helper variables for `.tfmigrate.hcl`:

```hcl
tfmigrate {
  migration_dir = "./tfmigrate"

  history {
    storage "s3" {
      bucket   = env.ATMOS_TFMIGRATE_HISTORY_BUCKET
      key      = env.ATMOS_TFMIGRATE_HISTORY_KEY
      region   = env.ATMOS_TFMIGRATE_HISTORY_REGION
      role_arn = env.ATMOS_TFMIGRATE_HISTORY_ROLE_ARN
    }
  }
}
```

The default history key is `tfmigrate/<stack>/<component>/<workspace>/history.json`. Atmos passes history settings to
`tfmigrate`, but does not persist or repair history itself. Configure durable S3, GCS, or CI-persisted local storage.

## Safety Checklist

Before committing migration work:

1. Confirm the migration addresses come from `atmos terraform state list`, not from code names alone.
2. Confirm the migration file targets the resolved component working directory and workspace.
3. Run `atmos terraform migrate plan` and inspect the post-migration Terraform plan.
4. Use history mode for hooks or CI workflows that may rerun.
5. Keep migration files and hook wiring in the same PR as the Terraform refactor they support.
6. Remove or disable one-shot hook wiring after the migration has safely run everywhere it is intended to run.

