“We should rewrite it” is one of the most expensive sentences in software.
Sometimes it is correct.
Often it is a reaction to pain we have not measured.
The existing application is slow to change. Bugs return. Nobody trusts a release. A new framework looks cleaner than understanding the old one.
That feeling is real.
It is not yet a migration plan.
First, name the pain
I separate complaints into evidence:
- Which changes take too long?
- Which defects repeat?
- Which modules create incidents?
- Which dependencies are unsupported?
- Where is data integrity at risk?
- What blocks deployment?
- What can the team no longer test?
- Which business capability cannot move?
“The code is messy” is a symptom description.
The decision needs a failure map.
A rewrite does not remove domain complexity
The old code contains years of decisions.
Some are bad.
Some look bad because the business rule is genuinely complicated.
When a rewrite ignores that distinction, the team rediscovers the rules through production bugs.
I look for:
- hidden status transitions;
- permission exceptions;
- migration history;
- billing edge cases;
- import and export contracts;
- reports the business quietly depends on;
- manual recovery procedures.
Those are requirements, even if no document calls them requirements.
I score six dimensions
1. Business continuity
Can the product pause while the new system catches up?
2. Boundary quality
Can one module be isolated behind a stable contract, or is every change global?
3. Testability
Can we capture current behavior before changing it?
4. Data risk
How difficult is migration, reconciliation, rollback, and dual operation?
5. Platform viability
Are the runtime and dependencies supported enough to stabilize?
6. Team ownership
Can the current team maintain the target architecture after the rewrite?
The answer is rarely one number.
The dimensions reveal where to start.
Stabilize before choosing
I prefer a short stabilization phase:
- reproduce the costly failures;
- add observability around the critical path;
- capture representative tests;
- document data and integration boundaries;
- remove one source of operational danger;
- measure whether change becomes safer.
This work is not wasted if a rewrite follows.
The tests, contracts, and failure map become migration assets.
Three strategies, not two
The decision is not only “fix” or “rewrite.”
Repair in place
Best when the platform is viable and pain is concentrated.
Incremental replacement
Move one bounded capability behind a new contract while the rest continues.
Full rewrite
Justified when core assumptions, platform support, data model, or operational boundaries make incremental work more dangerous than replacement.
Full rewrites need an explicit migration and rollback plan.
“Launch the new one” is not a rollback plan.
Define the strangler boundary
For incremental modernization, I want one capability with:
- clear input and output;
- measurable current behavior;
- limited data ownership;
- a routing or adapter seam;
- independent verification;
- a way back.
Examples might be:
- authentication;
- notifications;
- reporting;
- a public frontend;
- a single workflow;
- an external integration.
The best first boundary is valuable enough to matter and contained enough to learn from.
Watch for rewrite theatre
Red flags:
- framework names before a failure map;
- no inventory of business rules;
- no migration rehearsal;
- no reconciliation plan;
- no parallel-run decision;
- deadlines based on screen count;
- “clean architecture” with no owner;
- old and new systems changing independently without a contract.
A rewrite can create two legacy systems at once.
My decision rule
I rewrite when the evidence says the existing foundation prevents safe change and incremental boundaries cannot reduce that risk at a reasonable cost.
I repair when the product’s value is intact and the pain can be isolated.
I replace incrementally when continuity matters and the system has a usable seam.
The goal is not new code.
The goal is safer business change.
For a smaller first boundary, read how I modernize a React app without a big-bang rewrite. For release protection, read my production code-review checklist.
If your team is debating a rewrite, send me the failure map—not the preferred framework.
- #Legacy Systems
- #Modernization
- #React
- #Architecture
- #Technical Debt

Continue reading
Related field notes on engineering, SaaS, freelancing, and building dependable products.