Skip to content
← Back to blog
Engineering·Updated August 6, 2026·6 min read

Modernising legacy systems without the big rewrite

The full rewrite is the most expensive, riskiest path, and rarely the right one. How to modernise incrementally instead.

Every legacy system invites the same fantasy: tear it down and rebuild it clean. It's almost always a mistake. Big-bang rewrites are where budgets die, and the new system usually reinvents bugs the old one had already solved, years later and at several times the cost. The instinct is understandable: the old code is ugly, no one fully understands it, and a green field feels liberating. But the ugliness is often load-bearing.

Why rewrites fail

  • The old system encodes years of undocumented edge cases (the weird tax rule, the customer-specific discount, the workaround for a partner's broken API) that a rewrite quietly drops, then rediscovers as production incidents.
  • You ship nothing new for months, sometimes years, while the rewrite catches up to where you already were. The business doesn't stop needing features in the meantime.
  • Two systems in parallel doubles maintenance, not halves it. Every bug fix and every new requirement now has to land in two places.

Rewrite versus strangle, on the dimensions that decide it

Big-bang rewriteIncremental (strangler)
Time to first delivered valueLaunch day, months or years outThe first slice, usually weeks
If you are wrong about a decisionDiscovered late, expensive to unwindDiscovered in one slice, cheap to change
RollbackAll or nothingRoute traffic back, per slice
Business continuity during the workAt risk from the cutoverNever interrupted
Feature delivery meanwhileFrozenContinues
Systems to maintainTwo, until the day it landsTwo, but shrinking every slice
What happens if funding stops halfwayTwo half-systems, nothing shippedA working system, partly modernised

That last row is the honest argument. Rewrites are not usually killed by a technical failure; they are killed by a budget cycle, a reorganisation or a change of sponsor, and the incremental path is the only one of the two that survives being interrupted.

Why this matters

Modernisation is rarely a technical problem in isolation; it's a business-continuity problem. The legacy system is, right now, making money and serving customers. A rewrite asks the business to bet that fragile, low-visibility process against a multi-month project that delivers no value until the very end. That's a bad trade, and it's why so many rewrites are quietly abandoned halfway through, leaving the organisation maintaining two half-finished systems instead of one working one.

The incremental path

  1. 1.Strangle, don't replace. Put a façade in front of the legacy system; route functionality to new services one slice at a time, until the old core has nothing left to do.
  2. 2.Start at the seams. Modernise what changes or hurts most first, so the early work pays for itself.
  3. 3.Keep the data where it is, at first. Decoupling the data store is its own project; don't take it on at the same time as everything else.
  4. 4.Ship continuously. Every slice delivers value and de-risks the next, and at every point you have a working system you could stop on.

Choosing the first slice

The first slice sets whether anyone lets you do a second one, so pick it on evidence rather than on which code annoys the team most. Four criteria, and a good candidate meets at least three:

  • It changes often. Modernising code nobody touches buys you nothing; modernising the file with the most commits pays back immediately.
  • It has a clean boundary. Something you can put behind a façade without unpicking the data model on day one.
  • It hurts visibly. A slow checkout or a nightly job that keeps failing gives you a before-and-after number a non-technical sponsor can see.
  • It is reversible in one step. If routing traffic back is not a config change, it is the wrong first slice.

What to avoid first, however tempting: the data layer, anything with a regulatory audit trail, and the piece one person understands and is on holiday. Those come later, when the team has learned the system's real behaviour on something safer.

Where the incremental path goes wrong

Being honest about the failure modes of the approach I am recommending, because it has three:

The façade becomes permanent. Routing layers are easy to add and nobody is ever assigned to remove one, so a decade later there are three of them stacked up. Give each façade a written retirement condition when you create it.

The strangling stops halfway. The easy slices go first, the hard core stays, and the organisation quietly settles into maintaining both forever. This is the most common outcome in practice, and the guard is a named owner for the last slice rather than the first.

Nobody locks in existing behaviour. Legacy code encodes undocumented rules, so if you rebuild a slice without characterisation tests over the old path first, you will ship the same edge-case bugs the old system had already solved. Write the tests against the legacy system while it is still running.

A good modernisation is invisible to users and reversible at every step. A rewrite is a held breath until launch day.

A concrete example

A retailer with a 15-year-old monolith wants to modernise checkout. Instead of rebuilding the platform, they put a routing layer in front of it and rebuild only the payment flow as a new service. Traffic shifts gradually, the old path stays as an instant fallback, and the team learns the real-world quirks before touching anything else. Six weeks in, customers have a faster checkout and the business has taken on near-zero risk, the opposite of a two-year rewrite that ships nothing until it's done.

What this means for your team

Frame modernisation as a sequence of small, shippable, reversible bets, each justified on its own merits, the same build, buy, or AI thinking applied to an existing system instead of a greenfield one. Modern AI tooling genuinely accelerates the grind (understanding old code, mapping dependencies, drafting tests to lock in existing behaviour before you change it) but it accelerates a disciplined process; it doesn't replace one. If you're staring down a system everyone's afraid to touch, and wondering whether that's one of the signs you've outgrown your dev agency or just a question of choosing a software development partner who's done this before, we've done this before and can help you map the seams.

Frequently asked questions.

The old system encodes years of undocumented edge cases (the weird tax rule, the customer-specific discount, the workaround for a partner's broken API) that a rewrite quietly drops and then rediscovers as production incidents. You also ship nothing new for months or years while the rewrite catches up to where you already were, and running two systems in parallel doubles maintenance rather than halving it. In practice rewrites are usually killed not by technical failure but by a budget cycle, a reorganisation or a change of sponsor.

You put a façade in front of the legacy system and route functionality to new services one slice at a time, until the old core has nothing left to do. Start at the seams by modernising what changes or hurts most first, so the early work pays for itself. Keep the data where it is at first, because decoupling the data store is its own project. Ship continuously so every slice delivers value and de-risks the next, and at every point you have a working system you could stop on.

The first slice decides whether anyone lets you do a second one, so pick it on evidence. There are four criteria and a good candidate meets at least three: it changes often (the file with the most commits pays back immediately), it has a clean boundary you can put behind a façade without unpicking the data model, it hurts visibly so a non-technical sponsor gets a before-and-after number, and it's reversible in one step. Avoid the data layer, anything with a regulatory audit trail, and the piece only one person understands.

Three ways. The façade becomes permanent, because routing layers are easy to add and nobody is assigned to remove one, so give each façade a written retirement condition when you create it. The strangling stops halfway, with the easy slices done and the hard core left forever, so name an owner for the last slice rather than only the first. And nobody locks in existing behaviour, so write characterisation tests against the legacy system while it's still running or you'll ship the same edge-case bugs it had already solved.

The first slice typically lands in weeks, compared with a launch day months or years out for a big-bang rewrite. Take a retailer with a 15-year-old monolith modernising checkout: instead of rebuilding the platform they put a routing layer in front of it and rebuild only the payment flow as a new service. Traffic shifts gradually, the old path stays as an instant fallback, and six weeks in customers have a faster checkout while the business has taken on near-zero risk.