The checkout still ran on the old stack. Nobody loved that stack. Schema quirks, weekend batch jobs, a payment adapter that only three people could debug. Still, it took money. When the rewrite team flipped traffic on a Friday night, the new path looked clean in staging and wrong in production. Undocumented fee rules. A rare coupon path. A reconciliation job that only ran after settlement. Revenue did not care that the architecture was modern.
That is the failure mode we keep seeing when legacy system migration is sold as a cutover. The core still earns money. A big-bang rewrite bets the business on a single night.

This post is about how to leave a legacy platform without that bet. Coexistence migration, not cutover. Controls you can point at in a steering meeting, not vibes about “careful rollout.”
What breaks in a big-bang rewrite
Big-bang fails in predictable places.
Revenue and customer-facing paths break first. Checkout, renewals, claims intake, KYC handoffs, anything that touches money or a customer waiting on a screen. In India enterprise work we treat those as highest blast radius by default. Canaries belong away from known peak-load windows when you can choose the window.
Undocumented edge cases break next. The wiki is incomplete. The real rules live in code comments, support macros, and one person’s muscle memory. Staging never had the weird data. Production did.
Operational truth breaks last and hurts longest. Audit trails, settlement files, partner callbacks, overnight batches. If you switch writes before you can explain every side effect, you inherit incidents you cannot diagnose because half the evidence is on a system you just turned off.
A rewrite can still be the right end state. The mistake is making the end state the first production event.
What “without breaking what works” actually means
“Protect what works” is not a slogan. It is a control checklist.
- Coexistence window. Old and new run together under defined traffic and data rules. Cutover is a phase, not a night.
- Parity contract. Named comparisons, named owners, named exit signatures. “Looks fine” is not a gate.
- Traffic shaping. You move cohorts and percentages with config. You do not redeploy to undo a bad idea.
- Instant rollback. Revert is a routing change (or feature flag), not restore-from-backup theater.
- Sync plus reconciliation. Dual paths are allowed only while you can prove the stores agree, or explain every deliberate drift.
- Decommission as a deliverable. Turning the old system off is scheduled work with exit criteria, not a hope after hypercare.
If a plan cannot show those six, it is still a big-bang with better slides.
Phases and ownership still matter the way they do on any serious program: discovery that produces a decision, a thin production slice, harden, hypercare, then run. We wrote that delivery shape from discovery to hypercare as a sibling post. This one is about the migration mechanics inside those phases when the thing you are replacing still pays the bills.
The strangler fig pattern: intercept, route, grow the new edge
Martin Fowler popularized the strangler fig pattern for replacing a system the way a strangler fig grows around a host tree: wrap the old system, take work at the edges, and let the new implementation expand until the old core can be removed.
In practice the shape is simple.
Intercept. Put a facade, gateway, or routing layer in front of the legacy entry points you care about. Prefer seams you already have (API gateway, BFF, message entry) over inventing a second universe of proxies.
Route. Decide, per request or per message, whether work stays on legacy, goes to the new service, or runs in shadow (new computes, legacy still serves).
Grow the new edge. Ship vertical slices with contained blast radius and visible value. Do not boil the ocean behind the facade while traffic still hits the monolith for everything important.
The pattern is not magic. Without parity, traffic control, and a decommission plan, a facade becomes a permanent dual-maintenance tax. The rest of this post is those controls.
The coexistence ladder: shadow to decommission
Treat migration as a ladder. Skip a rung only when you can defend why.
| Stage | What happens | Exit signal |
|---|---|---|
| Shadow | New path computes; legacy still serves users | Diffs understood; no silent drift on critical fields |
| Canary | Small cohort or % on new path | Error, latency, and business metrics within budget |
| Move reads | New path owns reads for a bounded domain | Read parity stable; cache and auth quirks known |
| Move writes | New path owns writes for that domain | Write parity + reconciliation clean; rollback tested |
| Decommission | Legacy path removed for that domain | No remaining callers; licenses and runbooks updated |
Shadow before canary. Reads before writes when the domain allows it. Writes only when rollback is a config flip and reconciliation is already boring.
Vendor license calendars sometimes force timing. Treat that as a constraint on the calendar, not as a reason to skip parity.
Parity contracts: what you compare, how long, who signs
Parity is how coexistence stays honest.
What you compare. Business outcomes first (order total, eligibility decision, claim status), then key fields, then technical signals (error class, latency budget). Compare the paths users feel, not only JSON shape.
How long. Long enough to cover weekly and monthly cycles, not only a happy Tuesday. Settlement, billing, and batch calendars belong in the window. “Two sprints of green dashboards” is usually too short for money paths.
Who signs exit. Product signs “behavior matches what we sell.” Eng signs “diffs are explained or fixed.” Ops signs “we can run and roll back.” Finance or risk initials when money or regulated outcomes are in play. Keep both systems’ audit trails during dual-run so a dispute can be reconstructed. That is operational hygiene, not a privacy essay.
Write the contract before the canary. Expanding traffic without a contract is how teams “feel good” into an outage.
Traffic shaping and instant rollback
Traffic shaping is how a zero downtime migration stays reversible: cohort flags, percentage rollout, geography or tenant allowlists, path-based routing at the facade.
Instant rollback means the same control plane can send traffic back to legacy in minutes. If rollback requires restoring a database backup, rebuilding a release, or “hotpatching the monolith,” you do not have migration rollback. You have disaster recovery cosplay.
Practice the rollback in staging and once in production at low blast radius before you need it. The first time you rehearse should not be the incident.
Data sync: dual-write, CDC, outbox, and always reconciliation
While two systems coexist, data will try to diverge. Pick a sync posture on purpose.
| Approach | When it fits | Main risk |
|---|---|---|
| Short-lived dual-write | Same request can update old and new; window is brief; failure mode is clear | Partial success; ordering bugs; longer dual-write becomes a second legacy |
| CDC from legacy | Legacy remains system of record for a while; you need near-real-time projection | Schema weirdness; delete/update semantics; replay tooling |
| Outbox on the new edge | New services own writes and must publish reliably to others | Outbox table discipline; consumer idempotency |
Reconciliation always. Nightly or continuous jobs that count mismatches on critical keys. A human-readable exception queue. Ownership for clearing exceptions. Sync without reconciliation is faith.
Dual-write should be short-lived by design. If you cannot say when it ends, you are growing a new permanent coupling.
Slice selection: contained blast radius, visible value
Pick slices that shrink fear and create proof.
Contained blast radius. Prefer a bounded domain with clear ownership and limited fan-out. Avoid starting on the payment spine unless you have already proven the facade, parity, and rollback on something quieter.
Visible value. A slice leadership can see: faster change in one workflow, clearer audit, a partner integration that no longer needs a weekend hero. Pure plumbing slices stall because nobody outside eng can tell if they worked.
A good first slice is boring on purpose. Boring is how you earn the right to touch money paths later.
Decommission is a deliverable
Teams celebrate “new path live” and leave the old path half-dead. That is how license costs, patch debt, and dual runbooks become permanent.
Decommission work includes: remove callers, turn off jobs, archive data with a retrieval story, update runbooks and on-call, close vendor entitlements, and prove no silent dependency remains. Schedule it. Staff it. Give it exit criteria. Until legacy is actually gone for that domain, the migration is not done.
How we run this at Bluelupin
At Bluelupin we prefer legacy system migration as a strangler, not a weekend flip: grow a new edge, keep revenue paths safe, retire the old core on evidence. When we modernize a legacy enterprise platform, we do it in stages. New architecture beside the old one. Automated testing. Staged rollout and monitoring. Not a single flip. The control set is the same one this post describes: coexistence, parity, traffic shaping, sync with reconciliation, and decommission as real work.
If your platform still earns money and the rewrite pitch sounds like a weekend cutover, start with the ladder instead. Protect what works while you replace what must change.