Blog - Rewrite or Refactor? How We Decide When a System Has Reached Its Limit
Every software system eventually reaches a point where adding features feels like building on sand. Developers spend more time understanding existing code than writing new code. Bugs that get fixed in one place reappear somewhere else. New hires take months to become productive. At this point, someone always raises the rewrite question.
We have sat in this conversation with clients more times than I can count. A full rewrite is almost always the emotionally satisfying answer and almost never the right one. But "just refactor it" is not always the right answer either. Here is how we think through it.
Understand why the system is struggling
Before discussing solutions, we spend time diagnosing the real problem. Systems degrade for different reasons, and the cause shapes the remedy. A codebase written by a single developer who left two years ago needs different treatment than a system that was well-structured but has been extended far beyond its original scope.
Common causes we see: no automated test coverage (which makes every change risky), accumulated business logic in the wrong layer (usually the database or the frontend), dependencies on outdated libraries that can no longer be upgraded, and architecture that cannot accommodate the current load or feature surface.
Each of these has targeted solutions that fall short of a full rewrite.
The case for incremental refactoring
The core argument against rewrites is that the existing system, however messy, encodes years of business logic — including the edge cases nobody remembers to document. A rewrite discards that knowledge and rebuilds from the specification, which is always incomplete. You will spend the first year of the new system fixing bugs that the old system had quietly solved.
Incremental refactoring, done with discipline, can transform a struggling system without the risk of a big-bang replacement. We typically start by adding test coverage to the most critical paths, then extract and clean one module at a time while keeping the system running.
When a rewrite is genuinely the right call
There are situations where refactoring is not viable. If the platform the system runs on has been end-of-lifed and cannot be upgraded, if the data model is so fundamentally misaligned with current requirements that migrating it is as much work as starting fresh, or if the system has no test coverage and is too large to safely add it — these are cases where a well-planned rewrite, done in parallel with the running system, is justified.
The key phrase is "well-planned." The most dangerous rewrites are the ones where the team is so eager to escape the old code that they start building before they understand the requirements fully. We insist on spending the first phase of any rewrite project doing nothing but documenting the existing system's behaviour.
The conversation we have with every client
Ultimately, this is a business decision as much as a technical one. A rewrite carries higher short-term cost and risk. Refactoring carries lower risk but may be slower to deliver the outcome the business needs. We map both paths with honest estimates and let the client choose with full information.
In eight years, we have found that most struggling systems benefit more from disciplined, incremental improvement than from a fresh start. But the times when a rewrite was the right answer, it was clearly right — and moving decisively made all the difference.