Every developer has been in this meeting.
The codebase is struggling. Features are taking three times longer than they should. The team dreads touching certain files. A new developer joined two months ago and still is not fully productive because the system is so hard to understand. Someone finally says it out loud: maybe we should just rewrite the whole thing.
And then the room splits.
Half the team wants to burn it down and start fresh. The other half has been burned by rewrites before and knows how that story usually ends. Both sides are drawing from real experience. Both sides are right about something.
The truth is that neither refactoring nor rewriting is universally the correct answer. The right call depends on a specific set of conditions that are worth examining honestly before committing to either path. Because the cost of choosing wrong is significant in both directions.
Why Rewrites Feel Appealing and Usually Disappoint
The appeal of a full rewrite is psychological as much as technical.
A blank slate means no inherited constraints, no decisions made by people who have long since left the company, no embarrassing patterns you have been working around for years. You get to do it right this time. The excitement is real and it is not irrational.
The problem is that rewrites almost always take longer than estimated, frequently reproduce the same mistakes as the original in new clothing, and create a period of painful paralysis where the old system is still running in production while the new one is being built. You are maintaining two codebases simultaneously. The old one still needs bug fixes. The new one is perpetually almost ready.
Joel Spolsky wrote about this phenomenon over twenty years ago and called it one of the worst mistakes a software company can make. The lesson has not aged. Teams still walk into rewrites optimistically and emerge eighteen months later having delivered something that, on a good day, matches the functionality of what they replaced.
That is not an argument against ever rewriting. It is an argument for being brutally honest about why you want to.
The Conditions That Actually Justify a Rewrite
A rewrite makes sense when the problems you are dealing with are architectural rather than surface-level. Specifically, when the foundation of the system prevents you from building what the business needs and no amount of incremental improvement will change that.
A few conditions where we have found a rewrite to be the right call:
The data model is fundamentally wrong. If the way data is structured in the database does not reflect how the business actually works, and changing it would require touching nearly every part of the application, you may be better off redesigning from scratch. Trying to migrate a broken data model incrementally is one of the most painful things a development team can do.
The technology is genuinely end of life. Not just old, but abandoned. No security patches, no community support, incompatible with modern infrastructure. There is a difference between a codebase running on a framework that is a few versions behind and one running on something that has not had a commit in four years and has known unpatched vulnerabilities.
The business requirements have changed so fundamentally that the original system was solving a different problem. A codebase built for a single-tenant application that now needs to serve thousands of tenants is not just a refactoring project. The assumptions baked into every layer of that system are wrong for the new use case.
Nobody alive understands how it works. This sounds dramatic but it happens. If the system has no documentation, the developers who built it are gone, and the current team cannot confidently explain what a significant portion of the code does, you are not really refactoring anything. You are guessing. That is its own kind of risk.
Even when these conditions are met, the right rewrite is usually not a big bang replacement. It is a strangler fig pattern: build the new system incrementally alongside the old one, migrate functionality piece by piece, and decommission the old system gradually rather than all at once.
The Conditions That Point Toward Refactoring
Most of the time, the honest answer is that the system does not need to be rewritten. It needs to be cleaned up.
Refactoring makes sense when the core architecture is sound but the implementation has accumulated problems over time. Duplicated logic, inconsistent patterns, missing tests, functions that have grown to hundreds of lines, classes that have taken on responsibilities they were never designed for.
These problems are real. They slow teams down, they introduce bugs, they make onboarding harder. But they are fixable without replacing everything.
A few signals that point toward refactoring over rewriting:
Features can still be added, just more slowly than they should be. If the system is frustrating but functional, that is a refactoring problem. Slowness is a symptom of accumulated debt, not architectural failure.
The team understands the system well enough to work in it. If developers can explain what the code does, even if they do not like how it does it, that understanding is an asset. A rewrite discards it entirely.
The problems are concentrated in specific areas. Most codebases have a handful of modules that cause the majority of the pain. If you can identify them, you can target them. A full rewrite because one module is a mess is like demolishing a house because one room needs renovation.
The business cannot afford to stop shipping features. Rewrites require capacity. Real capacity, not theoretical capacity. If the business needs features delivered while the technical work is happening, a rewrite will either starve the product or starve itself.
The Honest Conversation Nobody Wants to Have
Here is the part that gets skipped most often.
Before deciding between refactoring and rewriting, someone needs to ask why the system got to this state. Not to assign blame, but because the answer tells you whether the problem is technical or organizational.
If the codebase is in poor shape because of accumulated pressure, changing requirements, and the normal entropy of software development, that is a technical problem with technical solutions. Refactor the worst parts, establish better practices going forward, allocate time for regular maintenance.
If the codebase is in poor shape because the team does not have a culture of code review, or because technical debt is always deprioritized in favor of new features, or because there is no ownership of quality, a rewrite will not fix any of that. You will have a new codebase and the same organizational dynamics that degraded the old one. In two years you will be having this meeting again.
The rewrite vs. refactor decision is a technical decision that often has a non-technical root cause. Getting that root cause right matters as much as the technical choice.
How We Actually Make the Call
When we are evaluating a struggling codebase, whether our own or one we have inherited from a client, we work through a few specific questions before recommending a direction.
Can we draw a clear boundary around the worst parts of the system and address them in isolation? If yes, that is almost always the starting point. Targeted improvement before wholesale replacement.
Is the core data model consistent with what the business actually needs today? If the answer is no and the gap is large, that shifts the calculation significantly toward a rebuild.
What does the team understand and what have they lost? Institutional knowledge of how a system works has real value. We weigh what a rewrite costs in lost knowledge against what it gains in technical freedom.
What does the business need over the next twelve months? A rewrite is a bet that the investment now pays off later. That bet only makes sense if the business has the runway and stability to absorb the transition period.
Most of the time we end up recommending a structured refactoring plan with clear targets and a defined timeline, rather than a full rewrite. Not because rewrites are always wrong, but because they are almost always oversold and underestimated by the teams proposing them.
The cases where we recommend a rewrite are real. But they are fewer than most teams think when they are standing in the middle of a painful codebase and imagining how good it would feel to start over.
Starting over feels good. Finishing the rewrite is where it gets hard.
If you are working through this decision on a specific system and want a second opinion on what the right path looks like, talking to a team that has done both is usually worth the conversation before committing either way.
Top comments (0)