Migrating a Legacy Monolith Without a Big-Bang Rewrite
A ten-year-old monolith had become too risky to change confidently, but the business couldn't absorb a multi-quarter rewrite freeze. Here's how the migration happened without either one.
The situation
The monolith worked, which was part of the problem — it had worked for a decade, accumulating undocumented behavior and implicit dependencies that nobody currently on the team had written. Every change carried a disproportionate amount of risk relative to its size, because nobody could say with confidence what else a given code path touched. The obvious fix — a clean rewrite — was also the most dangerous option: a multi-quarter freeze on new features while the business kept needing to ship.
The approach
We proposed a strangler-fig migration instead of a rewrite: new features are built in a modern service layer from day one, sitting behind a shared gateway in front of the legacy monolith. The gateway routes each request to whichever side — legacy or new — currently owns that capability, which means the two systems run side by side indefinitely rather than the team betting everything on a single cutover date.
Before any piece of the legacy core was touched or extracted, we built automated regression tests covering its actual behavior — not its documented behavior, since the documentation and reality had drifted apart years earlier. Those tests became the safety net that let us move pieces out of the monolith with confidence instead of hope.
Each extracted service was scoped to be independently tested, deployed, and owned going forward, rather than extracted as a single enormous block — smaller moves meant smaller blast radius if anything behaved unexpectedly once it was live.
The outcome
The business kept shipping throughout the migration — there was no freeze, no all-hands cutover weekend, no moment where the roadmap paused to let the migration happen. Each extracted service is independently tested, deployed, and owned, and the gateway means the remaining legacy surface keeps shrinking on its own schedule rather than a fixed deadline that would have forced corners to be cut.
Stuck between "too risky to touch" and "too big to rewrite"?
Let's talk through a migration path that doesn't require a freeze.