Migration Foundations · Wave Planning

Wave Planning

A real company doesn’t have one app to move — it has dozens or hundreds, all tangled together. You can’t move them all in a single heroic weekend (that’s the “big-bang” trap 👺 Gizmo the Gremlin loves). Wave planning is the craft of breaking the whole move into small, ordered, verifiable batches — waves — so that if anything goes wrong, only a little breaks, and every batch teaches you how to do the next one better. It’s the beating heart of a safe migration.

☺ Explain it like I’m 10

Imagine moving a whole school to a new building. You don’t carry every classroom at once in one chaotic afternoon — you move one small classroom first to learn the tricks, then a few related rooms together, then the rest. You always finish and check one batch before starting the next, so nobody loses their backpack. Those batches are “waves.”

🐿️🦫Your hosts for this topic: Nutty the Squirrel plans the batches from her inventory and dependency map, and Benny the Beaver actually moves each wave and builds the runbook — with 🐢 Timmy checking every cutover.

What a migration wave is

☺ Like you’re 10: A wave is one batch of things you move and check together before starting the next batch.

A migration wave is a group of related applications and their data, moved to the cloud together and validated before the next group begins. Each wave is a self-contained mini-project with its own plan, its own cutover, and its own rollback. A migration is simply a sequence of these waves — often called a wave plan or migration schedule.

The alternative is the big-bang migration: move everything at once, in one giant cutover. It sounds faster, but it stacks every risk into a single night with no way to undo just one part. Waves trade a little extra elapsed time for a lot less risk — and that trade is almost always worth it.

◆ Key idea

A wave is the unit of safe progress. Anything that goes into a wave must be able to move together, be tested together, and — if needed — be rolled back together. Get your wave boundaries right and the rest of the migration is mostly disciplined repetition.

Why move in waves

☺ Like you’re 10: Small batches mean small mistakes, faster learning, and no giant scary day.

1. It shrinks the blast radius

If a wave goes wrong, only that batch of apps is affected — not the whole business. A problem in Wave 3 doesn’t touch the apps already running happily from Waves 1 and 2. Small batches make failures survivable, which is the entire point.

2. It turns the move into a learning machine

The first wave is where you discover the surprises — a forgotten firewall rule, a slow database copy, a config nobody documented. You fix your tooling and runbooks, and roll those lessons into the next wave. Teams often call this the migration factory: by Wave 4, the same kind of app moves in a fraction of the Wave-1 time because the path is now paved.

3. It keeps the business running and spreads the load

Nobody can take a hundred apps offline on the same night, and no team can execute that safely. Waves spread the effort, the risk, the cost, and the change-fatigue on your people across weeks or months — while the lights stay on.

Step 1 — Start from discovery & dependencies

☺ Like you’re 10: You can’t sort the boxes into batches until you know what’s in every box and which boxes are tied together.

Wave planning is only as good as the map it’s built on. Before you can group anything, you need the outputs of discovery & dependency mapping from the assess phase: a full inventory of applications, and a dependency map showing which apps talk to which (which app calls which API, which apps share a database, what talks to that one server everyone forgot about). Nutty the Squirrel’s golden rule: you can’t move what you haven’t counted, and you can’t batch what you haven’t mapped.

⚠ Watch out for hidden dependencies

The dependency you don’t know about is the one that breaks a wave. An app quietly reading from a shared database, a nightly job on another server, a hard-coded IP address — miss it, and you’ll cut over an app whose lifeline is still back in Fort Rusty. Automated discovery tools (see the toolbox) exist precisely to surface these.

Step 2 — Group apps into waves

☺ Like you’re 10: Put things that belong together in the same batch — the toys that are always played with together should move together.

Now you sort the inventory into batches. There’s no single “right” grouping — you weigh several criteria at once. These are the ones that matter most:

Grouping criterionWhy it matters
DependenciesApps that talk to each other constantly should move together, or the chatter has to cross the slow, costly link between on-prem and cloud.
Business domain / ownerApps owned by one team (e.g. “payments”) share people and context, so they’re easier to plan, test, and support as a batch.
EnvironmentMove dev and test copies of an app before production — you rehearse the move on the safe copy first.
Risk & complexityGroup by how scary each app is, so you can put the easy ones early and the crown jewels late.
7 R strategyApps with the same R (all rehosts, say) can reuse the same tooling and runbook within a wave.
Compliance / data residencyRegulated workloads may need special handling or a specific region — keep them together so their controls are planned once.
Downtime windowApps that can only go offline in the same maintenance window (e.g. Sunday 2 a.m.) naturally batch together.

The golden rule: move tightly-coupled things together

If two apps are “chatty” — they call each other hundreds of times a second, or share one database — splitting them across two waves means that during the gap, every one of those calls has to travel between Fort Rusty and Cloudville. That adds latency (a slow round-trip) and can rack up egress fees. So the rule is blunt: tightly-coupled apps go in the same wave, or you accept a painful hybrid period between them.

Cut the estate where the seams are thin

The best wave boundaries fall between loosely-coupled groups — clusters of apps with lots of connections inside and only a few thin connections to the outside. Find those natural seams in the dependency map and cut there; you’ll minimise the cross-wave links you have to bridge temporarily.

Step 3 — Sequence the waves

☺ Like you’re 10: Move the easy, safe stuff first to practise, and save the most precious, most connected stuff for when you’re an expert.

Wave 1 is a pilot

Your first wave should be a pilot: the smallest, least-connected, lowest-risk, non-critical app you can find. Its job isn’t to move something important — it’s to prove the path: the landing zone works, the tools work, the team knows the runbook, and cutover-and-rollback both behave. Learn here, where a mistake costs nothing.

Ordering principles for the waves after the pilot

⚠ Mind the in-between (hybrid) state

While a migration is mid-flight, some apps live in the cloud and some are still in Fort Rusty — and they may still need to talk. Plan the temporary hybrid connectivity (a VPN or a dedicated link like Direct Connect / ExpressRoute / Interconnect — see patterns) so cross-wave chatter stays fast and secure until everything has landed.

Step 4 — Size each wave

☺ Like you’re 10: Not too big to check, not too small to bother — just right.

How many apps belong in one wave? The answer is a balance:

The right size depends on team capacity, how long your maintenance/cutover windows are, the risk tolerance of the business, and how complex the apps are. Early waves are deliberately small (you’re still learning); later waves grow as the factory speeds up.

◆ Rule of thumb: the “two-pizza wave”

A good wave is one a single focused team can plan, move, and verify inside one window without heroics — often a handful to a couple dozen apps, not a hundred. If a wave needs a war room and an all-nighter, it’s too big; split it.

Step 5 — Write the wave plan

☺ Like you’re 10: Write down the batches, the order, and exactly what to do — and what to do if it goes wrong.

The wave plan is the document that turns your grouping and sequencing into a schedule everyone can follow. For each wave it records:

The per-wave runbook

Under the plan sits the runbook: the precise, step-by-step checklist for executing this wave’s cutover — every command, every check, every go/no-go decision, and the exact steps to reverse it. Benny writes it, rehearses it, and refines it after every wave. A cutover without a written runbook is a cutover you’re improvising at 2 a.m.

Staggered waves over time Wave 1 pilot · smallest, safest app Wave 2 core, related apps Wave 3 the remainder Time Each wave: plan → migrate → validate → cutover → hypercare

Step 6 — Run a wave, end to end

☺ Like you’re 10: For each batch: set up the new room, do a practice run, make the switch, check it, watch it closely, and be ready to undo it.

Every wave repeats the same mini-lifecycle. This is where Benny and Timmy do their work:

Prepare & replicate

Build the target environment inside the landing zone, then start copying the data. For anything that can’t take much downtime, set up continuous replication so the cloud copy stays in sync with the live system right up to cutover (see data migration).

Rehearse the cutover

Do a test cutover — often on the dev/test copy — to prove the runbook works and to time it. A rehearsal turns unknowns into knowns before the stakes are real.

Cut over

Make the switch to the cloud version. How you flip the traffic is its own choice — big-bang vs phased, blue-green, or canary — all covered in architecture patterns. A wave and a cutover pattern work together: the wave decides what moves; the pattern decides how the switch happens.

Validate against RTO/RPO

Before anyone trusts the new version, verify it: does it work, is the data correct and complete (row counts, checksums), and did it meet the wave’s RTO/RPO targets? No green light until it passes.

Hypercare

Right after cutover, watch the wave closely for a while — extra monitoring, people on standby. Most problems show up in the first hours or days; hypercare is how you catch them fast.

Roll back if it fails

If validation fails and you can’t fix it in the window, execute the rollback / backout plan and return to the old system — no drama, because you planned for it. A cutover you can’t reverse isn’t a cutover; it’s a gamble. This is Timmy the Turtle’s single non-negotiable rule.

Step 7 — Retro, then improve the next wave

☺ Like you’re 10: After each batch, talk about what went well and what didn’t — then do the next batch a bit better.

Close every wave with a short retrospective: what surprised us, what slowed us down, what should change. Fold the answers straight into the tooling, the automation / Infrastructure-as-Code, and the runbook for the next wave. This is what makes the factory speed up — each wave is cheaper and faster than the last because you stop re-solving the same problems.

🦫 Benny’s workshop · 10 min

Take five apps you know (or invent them): a public website, its database, an internal HR tool, a nightly reporting job, and a legacy system nobody wants to touch. Sketch which depend on which, then sort them into 2–3 waves. Which is your pilot? Which two must share a wave? Which is the crown jewel you’d move last? Write one sentence defending your Wave 1 choice.

Common wave-planning mistakes (Gizmo’s traps)

☺ Like you’re 10: The usual ways a batch plan goes wrong — and how to dodge each.

Trap 👺Why it hurtsThe fix
Waves that are too bigCan’t be tested or rolled back in one window; a failure hits too much at once.Split until a wave fits one window with room to spare.
Ignoring dependenciesYou cut over an app whose database is still on-prem — it breaks or crawls.Batch by the dependency map; keep coupled apps together.
Moving crown jewels firstYour riskiest system moves when the team is least practised.Pilot small; save the critical systems for last.
No per-wave rollbackA failed cutover becomes an outage instead of a quick switch-back.Every wave ships with a written, rehearsed backout plan.
Waves that never endEndless re-planning; the estate is half-migrated for years, paying two bills.Time-box planning; start the pilot and learn by doing.
Forgetting to decommissionOld servers keep running (and costing) after the wave has moved.Make “decommission the source” the last step of every wave.

Each of these is a door Gizmo props open. Spot it, shut it.

A worked example: 12 apps, 3 waves

☺ Like you’re 10: Here’s a real-ish move, sorted into batches, so you can see the thinking.

Say an online retailer has twelve apps to move. After discovery, Nutty sorts them by dependency, risk, and business value into three waves — easiest and safest first, the revenue engine last:

WaveAppsMostly which R?Why here
Wave 1 · PilotInternal wiki, a static marketing site, the dev/test environmentsRehostTiny, non-critical, few dependencies — proves the landing zone and the runbook with nothing at stake.
Wave 2 · CoreInventory service + its database, the internal admin tool, the analytics/reporting jobRehost / ReplatformRelated back-office apps that share data; moving them together avoids chatty cross-cloud calls. The team is now warmed up.
Wave 3 · Crown jewelsThe customer storefront + checkout, the payments service, the product catalog they all readReplatform / RefactorRevenue-critical, tightly coupled, zero appetite for downtime — moved last, with the most rehearsal, and cut over with a blue-green switch and instant rollback.

Notice the logic: the payments service and the catalog it depends on land in the same wave as the storefront that needs them, the pilot risks nothing, and the whole thing is ordered so no app ever arrives before the thing it relies on.

🎬 At the Migration Academy
🦊

Foxy: We’ve got sixty apps to move. Why not just copy them all up this weekend and be done by Monday?

🐿️

Nutty the Squirrel: Because half of them are tied together in ways you can’t see yet. Let me sort them by my dependency map — the ones that chat constantly go in the same wave, the loners go early, the crown jewels go last.

🦫

Benny the Beaver: And we move Wave 1 — one tiny, boring app — first, just to prove my runbook works. If the pilot cutover is clean, I know the path is paved for the scary ones.

👺

Gizmo the Gremlin: Ugh, so slow! One big weekend, one big switch, no boring rollback plan. Live a little!

🐢

Timmy the Turtle: That “one big switch” is how sixty apps break at once with nowhere to retreat. Every wave gets a rollback plan, or it doesn’t go live. Small batches, verified — that’s the whole trick.

🐿️

Nutty the Squirrel: And after each wave we do a two-minute retro and make the next one faster. Nice try, Gizmo.

🐢 Timmy’s checkpoint

(1) In one sentence, what is a migration wave — and how is it different from a big-bang move? (2) Give two reasons two apps might belong in the same wave. (3) What should your first wave be, and why? (4) Name the mini-lifecycle steps of running a single wave. (5) Which one step must never be skipped, no matter how well the cutover seems to be going?

Check your answers
  1. A wave is a batch of related apps migrated and validated together before the next batch begins; a big-bang moves everything at once in a single cutover. Waves shrink the blast radius and let you learn as you go.
  2. Same wave when they’re tightly coupled (share a database or call each other constantly — splitting them forces slow, costly cross-cloud chatter), or they share an owner, environment, downtime window, compliance need, or R strategy.
  3. The first wave is a pilot: the smallest, least-connected, lowest-risk, non-critical app — because its job is to prove the landing zone, tools, and runbook while the stakes are zero.
  4. Running a wave: prepare & replicate → rehearse the cutover → cut over → validate against RTO/RPO → hypercare → roll back if it fails.
  5. Never skip the rollback / backout plan (and its validation). It’s what turns a failed cutover into a five-minute switch-back instead of an outage.