Why Most Rewrites Fail
Most rewrites fail not because the engineers are incompetent but because the work expands to absorb every known problem with the old system, the timeline slips past the point where the business can wait, and the new code turns out to have its own edge cases that only production use reveals. I have seen this pattern across dozens of teams. Understanding why it happens is the first step to avoiding it.
Written by Yashveer Singh, founder of Yashveer Labs.
What you actually need to know
- Most rewrites fail because the scope grows after the start, not because of technical problems.
- The old code knows things the team does not. Those things reveal themselves in production after the cutover.
- Parallel systems are expensive to maintain and the team eventually stops caring about the old one, leaving customers on a broken path.
- The second system effect is real. Engineers overcompensate for everything they hated about the first version.
- A rewrite that takes more than two times its original estimate is statistically unlikely to deliver on the original promise.
- Incremental replacement via the strangler fig pattern succeeds more often than big bang rewrites by a large margin.
| Rewrite type | Success rate | Primary failure mode | Better alternative |
|---|---|---|---|
| Big bang, full application | Low | Scope creep, timeline slip, stale old system | Strangler fig migration |
| Module rewrite with interface parity | Medium | Second system effect on the new module | Targeted refactor first |
| Parallel build with traffic shift | Medium-high | Permanent dual maintenance burden | Gradual strangler migration |
| Greenfield new product | Medium | Loses old product knowledge | Customer discovery before new build |
| AI-assisted rewrite | Medium | New code lacks production context | Refactor with AI assist, not full rewrite |
The core argument
Joel Spolsky wrote about this in 2000. The piece was called "Things You Should Never Do." The headline claim was that you should never rewrite from scratch. He was right about the mechanism even if the absolutism was overstated.
The old code is not just code. It is a compressed archive of every bug the system ever had, every edge case a customer ever hit, every business rule that was added quietly during an incident at 2 am. When you throw it away and start over, you throw that knowledge away too. The new code will rediscover it. In production. Under load. In front of customers.
This is not an argument against all rewrites. Some systems genuinely cannot be fixed. Some technical choices are so foundational that patching them is more expensive than replacing them. The argument is against the casual rewrite, the one that starts because the code is ugly and the team is frustrated and someone says "we should just start over."
The teams that succeed with rewrites share a set of disciplines. They define a fixed scope and hold it against every attempt to expand it. They build the new system incrementally, moving traffic gradually rather than cutting over all at once. They keep the old system fully functional until the new one is proven at scale. And they treat the old code as a specification, reading it carefully for behaviors they might miss rather than ignoring it.
The failure modes, named and specific
Scope creep
Every rewrite starts with good intentions. The scope is "just the payment module" or "just the authentication system." Then someone notices that the payment module calls a billing module that is also messy. The billing module calls the user management module. Three months in, the team is rewriting the entire application.
Each expansion felt reasonable. None of them were. The original estimate was for the payment module. The team is now building a new product.
The 70 percent wall
Rewrites follow a consistent pattern. The first 70 percent goes reasonably well. The basic flows work, the team is energized, the new codebase feels clean. Then the team hits the edge cases. The behaviors that only exist because of a bug that was fixed four years ago and nobody remembers why. The integration with the third party vendor that sends malformed data and the old code silently corrected for.
Each edge case takes longer than expected. The team is tired. The business is impatient. The last 30 percent of the work takes as long as the first 70 percent. If the original estimate was three months, the project ships in six. If it was six months, it ships in twelve, or it does not ship at all.
The stale old system
When a team is running two systems in parallel, attention naturally concentrates on the new one. Bugs in the old system get tagged as "will be fixed in the new version." New features go on the new system only. Customers on the old system notice. Support tickets accumulate. The old system becomes a customer relationship problem while the team is trying to ship the new one.
What a failed rewrite actually costs
| Cost category | Typical range | Notes |
|---|---|---|
| Engineering time, direct | 3x to 5x original estimate | Scope creep and edge case discovery |
| Opportunity cost of features not shipped | Hard to quantify | Often exceeds direct engineering cost |
| Customer churn during parallel period | 5 to 15 percent for visible products | Customers on the old system get worse service |
| Team morale and turnover | 1 to 2 engineers may leave | Demoralized teams are a real cost |
| Post-rewrite stabilization | 1 to 3 months of elevated incidents | New code meets production reality |
These numbers are not precise. They are directional, based on patterns I have seen across multiple projects. The point is that a failed or delayed rewrite is never just a schedule slip. It is a compounding cost across multiple dimensions simultaneously.
What to look for before approving a rewrite
- A written scope definition that has been reviewed and agreed to by all parties.
- An estimate that includes a fifty percent contingency for edge case discovery.
- A traffic migration plan, not a cutover date.
- A plan for maintaining the old system at minimum viable quality during the transition.
- A cancel condition, a point at which the team will stop and reassess rather than continuing to sunk-cost the project.
- A list of the known behaviors in the old system that the new system must replicate.
- A rollback plan that is executable within four hours.
Expert opinion
Every rewrite I have seen start with confidence has ended with a story about how it was harder than expected. The teams that succeed are not more talented. They are more disciplined about scope and more honest about what they do not know about the old system. The ones who fail are usually the ones who were most confident at the start.
>
Yashveer Singh, founder of Yashveer Labs
How this played out on a real project
A mid-stage SaaS brought me in to assess a rewrite project that had been running for nine months against a four-month original estimate. The team had rewritten about sixty percent of the application. The remaining forty percent included the billing system, the permission model, and the real-time notification layer, each of which was harder than expected.
The old system was still running. New customers were being onboarded to the new system. Existing customers were on the old system, which was receiving minimum viable maintenance. Support ticket volume for the old system was up forty percent from six months ago.
We made the call to stop the big bang approach and switch to a strangler fig model. The new system would absorb one module at a time, moving existing customer traffic incrementally. The rewrite did finish, fourteen months after it started, with a gradual migration rather than a cutover.
The lesson was not that the rewrite was wrong. It was that the big bang approach made it fragile. The strangler fig approach would have delivered the same outcome with less risk and probably in a shorter real-world timeline, because the parallel system problem would have been avoided.
For the decision framework that should have been applied before this project started, when to refactor and when to rewrite covers the cost-based analysis that makes this call analytical rather than emotional. For the migration strategy that replaces big bang rewrites in most cases, big bang vs gradual migration gives the full decision map.
Common mistakes
- Treating scope expansion as additive rather than multiplicative. Each new module added to the scope does not add its own estimate. It adds its own estimate plus the integration surface with everything already in scope.
- Setting an ambitious timeline to get approval and living with the optimism afterward. The estimate the founder approved was wrong from day one.
- Stopping maintenance on the old system before the new one is ready. Customer experience degrades and the old system becomes a liability at exactly the wrong time.
- Not reading the old code as a specification. The old code knows things you do not. Treat it as the most complete documentation you have.
- Assigning the rewrite to the most excited engineers rather than the engineers who understand the old system best. Enthusiasm without knowledge rediscovers every edge case in production.
- No cancel condition. The project continues past the point of reasonable return because stopping feels like failure. Stopping at the right moment is a decision, not a defeat.
- Overengineering the new system to avoid the mistakes of the old one. The second system effect is real and it compounds timelines.
- Cutting over on a hard date regardless of readiness. Hard cutover dates create pressure to ship incomplete systems.
A nine-week decision and planning process
- Week one. Document the cost of the existing system. Hours per sprint in workarounds, incidents per quarter, features blocked or slowed.
- Week two. Read the old code as a specification. Document every behavior that is not obvious from the interface.
- Week three. Write the scope definition. Sign off required from engineering lead, product lead, and founder.
- Week four. Build the traffic migration plan. Decide on strangler fig, percentage routing, or feature flag approach.
- Week five. Write the cancel condition. What metrics, at what threshold, will trigger a reassessment?
- Week six. Estimate with fifty percent contingency explicit and named. Present to founder with the contingency included.
- Week seven. Build the rollback plan. Test it before the first migration step.
- Week eight. Begin the first migration increment. One module, with old system still live and receiving traffic.
- Week nine. Measure and assess. Is the new module behaving as expected? Are the edge case discoveries within the expected range? Decide whether to continue.
The companion read for the ongoing maintenance discipline is the tech debt ledger post, which shows how to track the decision to rewrite versus refactor as a running cost analysis rather than a one-time judgment call.
Frequently asked
Closing note from the author
I keep these closing notes short on purpose. Most engineers writing about this topic are not the engineer you want to hire. I might be. Yashveer Singh, founder of Yashveer Labs. The contact channel is Instagram. The proof is the portfolio. The standard is in the work. If we are aligned, you will know within five minutes of the first message.
Posts that line up with this one.
- Tech Debt and Refactoring
Migrating From Express to Fastify or NestJS or Beyond
Express still works but it shows its age in production. Here is when to migrate, which framework to migrate to, and how to do it incrementally without breaking the application that customers depend on.
- Tech Debt and Refactoring
Migrating From REST to GraphQL: A Strategic Read
GraphQL solves real problems but introduces its own. The migration from REST to GraphQL is not a performance upgrade; it is an architectural shift. Here is when it is worth it and how to do it without breaking existing clients.
- Tech Debt and Refactoring
Mutation Testing: A Discipline Worth Considering
High code coverage does not mean good tests. Mutation testing reveals whether your tests actually catch bugs. Here is what it is, when it adds value, and how to introduce it without adding meaningless overhead.
- Tech Debt and Refactoring
Refactor Stories That Killed a Startup
Refactoring is necessary and valuable. It is also one of the most reliable ways to destroy momentum at the wrong moment. These are the patterns that turn a reasonable engineering goal into a business catastrophe.