There is a specific kind of system that makes cloud migration genuinely hard: the one that cannot stop. Not "we'd prefer not to take downtime" — actually cannot, because a maintenance window means transactions that never happened and messages that quietly disappear while the lights are off.

For those systems the weekend cutover is not a plan, it is a gamble with no rollback path. The alternative is to run the old on-prem platform and the new cloud platform at the same time, in production, serving real traffic, with the ability to shift load in either direction in seconds. This post is about how that is actually wired — the networking underneath it, the guarantees that stop messages being lost in the seam, and what makes rollback a routine operation rather than an emergency.

The two problems nobody warns you about

Overlapping address space. On-prem networks were addressed years ago, by people who had no reason to imagine a cloud VPC. It is extremely common to discover that the private ranges on both sides overlap — the same subnet exists in two places, meaning packets cannot simply be routed between them. Re-addressing a live on-prem estate is not a realistic option, so the practical answer is NAT at the boundary: each side is presented to the other through a translated, non-conflicting range, and neither has to renumber.

DNS is a bad cutover switch. The instinct is to shift traffic by changing DNS records. It works, slowly, and it fails badly: resolvers and client libraries cache far beyond the TTL you configured, so a rollback that should take seconds takes as long as the worst-behaved cache in the chain. Traffic shifting belongs at a gateway you control, where the routing decision is made per request and a change takes effect immediately.

If your rollback plan depends on DNS propagation, you do not have a rollback plan — you have a waiting period.
PARALLEL TOPOLOGY clients edge gateway weighted routing per-request decision 95% 5% ON-PREM legacy app system of record NAT 10.0.0.0/16 → 100.64.1.0/24 CLOUD VPC replica store new services NAT 10.0.0.0/16 → 100.64.2.0/24 private link VPN / direct connect CDC replication one direction only durable log retained, replayable both sides consume independent offsets
on-prem — still the system of record early on cloud — real traffic, real load, reversible

One rule that prevents most of the pain: single write authority

The temptation when running two platforms side by side is to let both write to their own database and reconcile afterwards. This is the fastest route to split-brain: two records for the same entity, both plausible, both partially correct, with no principled way to decide which one wins.

The discipline that avoids it is simple to state and requires real restraint to hold: at any moment, exactly one side owns writes for a given entity. Replication runs one direction only, from the owner to the follower. Migrating a capability means moving that ownership deliberately — never letting both sides hold it at once, even briefly.

This is also what makes rollback safe. If the cloud side never had write authority for an entity, rolling its traffic back to on-prem cannot lose anything, because on-prem's copy was authoritative the whole time.

Shifting traffic in stages you can reverse

With the topology in place, the migration becomes a sequence of small, reversible moves rather than one large irreversible one. Each stage answers a different question.

  • Stage 0 — mirror. The cloud path receives a copy of real production traffic but its responses are discarded. Nothing user-facing depends on it. This is where you find the configuration mistakes, the missing certificate, the timeout that is wrong by an order of magnitude.
  • Stage 1 — shadow compare. Same mirrored traffic, but now both responses are captured and diffed. Divergence is logged with enough detail to reproduce. You are not looking for zero differences — you are looking for zero unexplained differences.
  • Stage 2 — canary. A small, real percentage of traffic gets the cloud response for real. Start with the least destructive operations. Watch error rate, latency percentiles, and business metrics, not just infrastructure dashboards.
  • Stage 3 — majority. Weight moves up in increments, with a defined soak period at each step. The soak matters more than the increment size: some failures only appear across a full daily cycle.
  • Stage 4 — full cutover, then decommission. On-prem keeps running, cold, for a defined period after 100% — because the ability to go back is worth more than the hardware it occupies.
TRAFFIC STAGES stage 0 mirror 0% live responses discarded stage 1 shadow compare 0% live diffs logged stage 2 canary 5% live safest operations stage 3 majority 25 → 50 → 75% soak at each step stage 4 full cutover 100% live on-prem kept cold rollback — weight change at the gateway, effective in seconds safe at every stage because write authority never moved early
forward — each step small enough to be boring backward — reversible at every stage, no DNS wait

Not losing messages in the seam

"No packet loss" is the requirement people state, but in a migration the losses rarely happen on the wire. They happen at the edges of the change: a connection cut mid-request, a message consumed by a process that then died, an event delivered twice and applied twice. Four mechanisms cover almost all of it.

Connection draining. When a node stops taking traffic, it must finish what it already accepted before shutting down. Removing an instance from rotation and killing it in the same breath is the most common self-inflicted cause of "lost" requests during a migration.

A durable log rather than point-to-point delivery. If events live in a retained, replayable log, both platforms can consume the same stream at their own offsets. Nothing is destroyed on read, so a consumer that fails can resume, and a cloud service that was behind can catch up without anyone re-sending anything by hand.

Idempotency at every consumer. Retries are how a distributed system survives, which means duplicate delivery is normal rather than exceptional. Every operation carries a stable idempotency key, and consumers record what they have already applied — so a redelivered message becomes a no-op instead of a double charge.

Continuous reconciliation. A job that compares both sides on a schedule and reports drift is the only thing that turns "we believe nothing was lost" into "we checked." Run it from the first day of parallel operation, not the week before cutover — its value is the trend line, not the single reading.

NO LOSS IN THE SEAM request + idempotency key durable log retained · replayable not destroyed on read on-prem consumer own offset checks processed keys cloud consumer own offset checks processed keys on-prem state cloud state reconcile scheduled diff drift reported trend, not snapshot
both sides consume the same stream, independently idempotency + reconciliation turn belief into evidence

Making rollback boring

A rollback plan that exists only in a document is not a rollback plan. Three things make it real.

It has to be one action. Changing a weight at the gateway, applied immediately, with no coordinated multi-team sequence and no cache to wait out. If rolling back requires six steps in the right order, it will not be done calmly at 3am.

It has to be rehearsed. Trigger a rollback deliberately, during business hours, while the stakes are low — at every stage, not just once at the start. The first real rollback should be the fifth time the team has done it, not the first.

Its trigger has to be defined in advance. Error rate above a threshold for a sustained window, latency past a percentile, a reconciliation delta beyond tolerance. Written down before the stage begins, so the decision to roll back is a reading of a number rather than an argument between tired people.

What I'd tell someone starting this today

  • Audit address space before you plan anything else. Overlapping CIDR ranges are discovered late and reshape the whole design; NAT at the boundary is usually cheaper than renumbering a live estate.
  • Never let both sides own writes for the same entity. Bidirectional replication as a migration strategy creates a reconciliation problem worse than the migration itself.
  • Put traffic control at a gateway, not in DNS. The value is not in shifting traffic — it is in shifting it back immediately.
  • Shadow compare before canary, always. Finding a divergence with zero customer impact is worth far more than finding it 5% of the way into production traffic.
  • Run reconciliation from day one of parallel operation. Its purpose is the trend line — a single check the week before cutover tells you almost nothing.
  • Keep the old platform warm longer than feels necessary. Decommissioning is the only genuinely irreversible step in the entire project.

Done this way, the migration stops being an event with a date on it and becomes a slow, visible, reversible shift in a number. The day traffic reaches 100% is not dramatic — and that lack of drama is the entire point. If your platform cannot take a maintenance window, an honest map of where the write authority, idempotency and reconciliation gaps sit is usually the cheapest first step, well before any workload actually moves.