Migration Planning skill for Claude Code
Phased migrations that ship, roll back, and finish. Claude plans migrations so they finish: a quantified why, a machine-readable inventory that becomes the burn-down, a strategy with a named seam, and phases that each ship to production with numeric exit criteria and a rehearsed rollback. Shadow comparisons and data reconciliation guard correctness, CI blocks new use of the old path, and the plan carries a dated step that deletes the old system.
- name
migration-planning - size142 lines · ≈1,800 tokens
- files1
- licenseMIT
- updated
What Claude sees before loading it
This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.
description: Plans large software migrations such as framework or language changes, major version upgrades, database or cloud moves, and monolith-to-service splits, by inventorying everything affected, choosing a strategy (big bang, strangler fig, parallel run, branch by abstraction), defining phases that each ship and can be rolled back, dual-run and comparison checks, cutover criteria, and a tracking dashboard. Use when the user asks to plan a migration, rewrite, platform move, or upgrade too large for one PR, or when a migration has stalled half-done. Try asking
- Plan our move from the legacy billing monolith to the new invoices service
- We need to migrate 300 files from moment to date-fns — how do we phase it?
- Our Postgres-to-DynamoDB migration stalled at 70%. Make a plan to finish it
Use it when
- A framework, language, database, or platform change is too big for one PR
- A monolith split or service extraction is being planned
- A migration is stuck half-done with two systems running
- Leadership needs phases, risks, and dates for a rewrite
Skip it when
- The upgrade is a routine dependency bump — use dependency-upgrades instead
- You are executing a mechanical transform across files — use codemods instead
How to check the result
Every phase in the plan ships independently, states numeric exit criteria and a timed rollback, and the inventory count reaches zero before the dated decommission step.
The common mistake it prevents
Starting with the easiest slice instead of a representative one, so phase one proves nothing about auth, data or deployment and the hard problems surface late.
A migration plan is good when every phase ships to production on its own, has a measured exit criterion and a rollback that has been rehearsed, the inventory says exactly what is left at any moment, and there is a dated step that deletes the old path. The most common failure is not a bad cutover but a migration that stops at 80% and leaves two systems forever.
Workflow
- [ ] 1. State the why, the end state, and what "done" deletes
- [ ] 2. Inventory: every usage, dependency, consumer, data store, owner
- [ ] 3. Choose the strategy (table) and the seam where old and new meet
- [ ] 4. Phase plan: small shippable steps, riskiest/most representative first
- [ ] 5. Verification per phase: dual-run, diff, metrics, exit criteria
- [ ] 6. Rollback per phase; rehearse the first one
- [ ] 7. Tracking: burn-down of inventory items; decommission date
- [ ] 8. Review with owners; get explicit sign-off before any cutover
1. Why and end state
Write three lines: the problem with the current system (with numbers: cost, incidents,
EOL date, velocity), the target end state, and the deletion that defines done (“the
legacy-billing service and its database are shut down”). If the why is weak, recommend
not migrating; a stalled migration is worse than none.
2. Inventory
Build a machine-readable list; it becomes the burn-down.
# Framework/library usage (example: moment -> date-fns)
rg -l "from 'moment'|require\('moment'\)" src | wc -l
rg -c "moment\(" src --sort path > inventory/moment-usages.txt
# Endpoints served by the old service
rg -n "@(Get|Post|Put|Delete)\(" legacy-api/src | wc -l
# Consumers of a database table
rg -n "\binvoices\b" --type-add 'sql:*.sql' -t sql -t ts -t py .
Columns: item, owner, complexity (S/M/L), risk (data, money, auth), traffic, dependencies, status. Include non-code items: cron jobs, dashboards, alerts, runbooks, IAM roles, DNS, secrets, docs, client SDK versions in the wild. Unknown consumers (logs show calls from unlisted IPs or user agents) are the top risk; find them before phase 1.
3. Strategy
| Strategy | Use when | Avoid when |
|---|---|---|
| Strangler fig (route by route behind a facade/proxy) | Services, APIs, web apps with routable units | No interception point exists |
| Branch by abstraction (interface in code, swap implementations behind a flag) | Libraries, data access layers, in-process components | The abstraction would be huge and leaky |
| Parallel run / shadow (run both, compare, serve old) | Correctness-critical logic: billing, pricing, search ranking | Side effects cannot be suppressed in the shadow path |
| Expand and contract (add new schema, dual-write, backfill, switch reads, remove old) | Database and schema changes, data moves | — (default for data) |
| Incremental codemod (mechanical transform in batches) | Syntax/API upgrades (framework versions, language features) | Semantics differ case by case |
| Big bang | Small surface, low traffic, easy full rollback, or forced by EOL with tiny scope | Anything with data migration or many consumers |
Name the seam: the proxy route table, the interface, the feature flag, or the read/write switch where traffic moves from old to new. No seam, no incremental migration.
4. Phases
Rules for phases:
- Phase 0 builds the seam and observability (facade, flag, comparison logging), with no behavior change.
- Phase 1 is a real but low-risk slice that is representative (exercises auth, data, deployment) — not the trivial hello-world route. It proves the path.
- Each phase is days to two weeks, ships to production, and leaves the system releasable.
- Freeze new usage of the old path early: lint rule or CI check that fails on new imports
of the old API (
no-restricted-imports, a grep check in CI). - Data phases follow expand → dual-write → backfill → verify → switch reads → stop old writes → contract, each a separate deploy.
| Phase | Scope | Exit criteria | Rollback |
|---|---|---|---|
| 0 | Proxy in front of legacy-api; per-route flag; diff logging | 100% traffic through proxy 7 days, p99 +<5 ms | Remove proxy route (DNS) |
| 1 | GET /invoices (read-only, 12% traffic) on new service | Shadow diff < 0.01% for 7 days; error rate <= legacy | Flip route flag to legacy |
| 2 | Invoice writes with dual-write | Reconciliation job zero mismatches 14 days | Flag to legacy writes; new store ignored |
| 3 | Remaining 31 routes in 4 batches | Per batch as phase 1 | Per-route flag |
| 4 | Decommission legacy-api + DB (snapshot kept 90 days) | No traffic 30 days | Restore from snapshot (rehearsed) |
5. Verification
- Shadow / dual-run: send copies of real requests to the new path, compare responses (normalize timestamps, ordering, IDs), log diffs with request IDs, and do not let the shadow path cause side effects (no emails, no payments; use dry-run modes).
- Data reconciliation: row counts and checksums per partition, sampled field-level comparison, invariants (sums of money match to the cent).
- Metrics: latency p50/p99, error rate, saturation, business KPIs (orders/min) on both paths, with dashboards built in phase 0.
- Exit criteria are numbers and durations, agreed before the phase starts.
6. Rollback
Every phase lists how to go back, how long it takes, and what data reconciliation is needed after a rollback. A rollback that has never been executed is a hope: rehearse the first one in staging and time it. Irreversible steps (dropping old tables, deleting buckets, revoking old credentials) are separate, late, and require explicit user confirmation plus a verified backup.
7. Tracking
Track the inventory burn-down weekly (items remaining by status and owner), diff rate, and phase status. Put the decommission date on the plan from day one and review it when phases slip.
Gotchas
- Starting with the easiest slice proves nothing; start with a representative one.
- New features keep landing on the old system during the migration. Decide the policy (build new only on new path after phase N) and enforce it in CI.
- Dual-write without reconciliation silently drifts. Always run a comparison job.
- Time zones, encodings, rounding, sort order, and null handling cause most shadow diffs; budget time for them.
- The “temporary” compatibility layer becomes permanent without a dated removal task.
- Rewrites of large systems from scratch with a long freeze rarely finish; prefer incremental strategies unless the surface is small.
Output
The plan document, structured as:
# Migration: <old> -> <new>
**Why:** <problem with numbers> · **End state:** <target> · **Done means deleted:** <old thing>
**Strategy:** strangler fig via <seam>; data via expand-and-contract
**Inventory:** 47 items (link to inventory file) — 9 L, 21 M, 17 S; 3 unknown consumers to resolve
**Phases:** table with scope, exit criteria, rollback, owner, target date
**Verification:** shadow diff dashboard, reconciliation job, KPIs
**Guardrails:** CI check blocks new imports of the old client from phase 1
**Risks:** top 5 with mitigations · **Decommission date:** 2027-03-31
**Sign-off:** owners listed; cutover steps require explicit approval About this skill
Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.