Skip to content

Frontend Architecture

The Rewrite You Will Regret

Rewrites get underestimated by 3x because the old system refuses to stand still while you rebuild it. When rewriting is genuinely right, when it is not, and how to make the call honestly.

By Anshul Kapoor·August 2026·5 min read
ArchitectureLegacy CodeTechnical DebtEngineering Decisions
LinkedIn

TL;DR

  • Rewrites run 3x over estimate because the old system keeps moving while you rebuild it. You are chasing a target that accelerates.
  • Most rewrite decisions are made from frustration, not analysis. "We cannot build fast enough" is usually a team problem a rewrite will not fix.
  • The old code's ugliness is partly load-bearing. Those weird conditionals are fixes for real incidents your rewrite has not met yet.
  • Before rewriting, demand the strangler option be explicitly rejected with reasons. Incremental replacement wins far more often than it loses.

The most tempting decision in software

Every engineer who has spent six months inside a legacy codebase has felt it. The build is slow, the patterns are ancient, every feature takes three times longer than it should, and somewhere in the middle of tracing yet another bug through four layers of indirection, the thought arrives fully formed: it would be faster to rewrite this.

It is the most seductive sentence in engineering, and it is almost always wrong in a specific, predictable way. Not because rewrites never work. Because the version of the rewrite you are imagining, clean, fast, unburdened, is not the rewrite you will actually get.

The rewrite you will actually get is a second system that has to reach feature parity with a first system that refuses to hold still, while the business keeps asking why new features stopped shipping.

Why the estimate is off by 3x

The standard rewrite estimate is built on a quiet assumption: the old system is a fixed target. Count its features, estimate rebuilding them, add some buffer. Six months.

But the old system is not fixed. It is running in production, serving customers, and accumulating changes the entire time you are rebuilding it. Every bug fixed in the old system is a bug your rewrite must also fix. Every feature shipped there, because the business cannot actually pause for six months, widens the gap you are trying to close. You are not walking toward a finish line. You are chasing a runner who started years ahead of you.

Then there is the knowledge you cannot see from the outside. That bizarre conditional handling a date edge case exists because of an incident in 2021 that nobody documented. The old code is ugly, and some of that ugliness is load-bearing. A rewrite discards the fixes along with the mess, and rediscovers each one the same way the original team did: in production, one incident at a time.

Six months becomes eighteen. Not through incompetence. Through arithmetic the original estimate refused to do.

You are not walking toward a finish line. You are chasing a runner who started years ahead of you.

Frustration is not analysis

Watch how rewrite decisions actually get made, and the pattern is uncomfortable. They almost never start with analysis. They start with pain, months of it, and then reasoning gets assembled backwards to justify the escape.

"We cannot build fast enough" is the most common justification, and it deserves the most suspicion. Slow delivery has many causes: unclear requirements, thin test coverage, no deployment automation, too much work in progress, ownership nobody can name. A rewrite fixes none of these. A team that ships slowly in the old codebase will, after the honeymoon quarter, ship slowly in the new one, because the constraint was never the code.

The honest test: write down, specifically, what the rewrite makes possible that the current system cannot do. Not "cleaner" or "modern." Specifically. If the list is short and vague, you do not have a rewrite case. You have burnout wearing an architecture document, and burnout is worth addressing directly, not with two years of parallel system maintenance.

A team that ships slowly in the old codebase will ship slowly in the new one, because the constraint was never the code.

When a rewrite is genuinely right

Sometimes it is, and pretending otherwise would be its own dishonesty. The legitimate cases share a shape: the constraint is structural, and no sequence of incremental changes can remove it.

The platform is actually dying. The framework is end-of-life, the runtime is unsupported, the vendor is gone. You physically cannot hire people to work on it, and every security patch is an archaeology project. That is not frustration. That is a wall with a date on it.

The architecture forbids the product's future. Not "makes it awkward," forbids it. A single-tenant system that must become multi-tenant. A desktop codebase that must become a service. When the change touches every module because the old assumption is baked into every module, incremental and rewrite converge into the same amount of work, and the rewrite is at least honest about it.

The system is small enough to actually finish. A rewrite of something one team can rebuild in one or two quarters, with the old system frozen, is a different animal from a multi-year platform migration. Scope is the difference between a decision and a gamble. Most rewrite disasters are size disasters.

Notice the common thread: each case is an argument about constraints, not about code quality. Ugly code is never, by itself, a rewrite justification. Ugly code that provably cannot support the next three years of the roadmap is.

The strangler option

Between "live with it" and "rewrite it" sits the option that wins most often and gets chosen least: replace the system incrementally, piece by piece, while it keeps running. The strangler fig pattern, named for the tree that grows around its host until the host is gone.

Put a seam in front of the old system. Route one workflow at a time to new code. Each piece ships to production within weeks, gets validated against real traffic, and starts paying back immediately. There is no eighteen-month tunnel with a big bang at the end. There is no big bang at all. If priorities change mid-migration, you stop, and everything already moved keeps working. Compare that to an abandoned half-rewrite, which is worth exactly nothing.

It is not free. You maintain a routing layer, some duplication, and the discipline to actually finish rather than leaving a two-headed system forever. Those costs are real. They are also small next to the failure mode of the big rewrite, which is total.

So make the strangler option the default that must be argued against. Before any ground-up rewrite is approved, someone should have to explain, specifically, why incremental replacement will not work here. Sometimes there is a real answer. The assumption is baked into every module, there is no seam to cut along. Fine. But most of the time, the honest answer is that the strangler is slower to feel done, and feeling done is not an engineering requirement.

An abandoned half-rewrite is worth nothing. A half-finished strangler migration is half the value, already shipped.

How to decide without fooling yourself

A short list of questions that separate rewrite decisions from rewrite rationalizations.

What, specifically, can the new system do that the old one cannot? If the answers are adjectives, stop.

What happened the last time this organization ran a project longer than six months? Rewrites are delivered by the delivery culture you already have, not the one you wish you had.

Who maintains the old system during the rewrite, and have you actually staffed that? If you are assuming it will need nothing, it will not need nothing.

Why is the strangler approach wrong for this system? Demand a specific answer.

If the rewrite were banned, what would you do instead? The answer to that last question is usually a pretty good plan, which tells you something.

The teams that get this right are not the ones that never rewrite. They are the ones that treat "rewrite" as a claim requiring evidence, spend that evidence-gathering on the real constraints, and choose the boring incremental path whenever the evidence permits it. The rewrite you will regret is the one chosen because the old code was annoying. The one you will not regret is the one chosen because every alternative was examined and failed.

If the rewrite were banned, what would you do instead? The answer is usually a pretty good plan.

Found this useful?

Share it with someone who might be wrestling with the same problem.

ShareLinkedIn

Thanks for reading.

If this resonated and you're hiring for Senior/Staff Frontend roles, I'd love to chat.