Refactor or rewrite: the decision that can block your roadmap

29/09/2025
technician restoring a painting

Each new feature takes longer than it should. The team asks for time to "clean up." A point is reached where a decision must be made: refactor or rewrite? Both options carry real risks. Making the wrong choice is costly.

The roadmap says one thing. Technical reality says another.

The product team wants to release three features this quarter. The development team says that, as the system stands, they'll be lucky to release one. The conversation always ends up at the same point: "The codebase just won't let us move forward."

At that point, two options appear on the table. Refactor: improve the current system without stopping it, cleaning and restructuring what's holding it back. Or rewrite: start from scratch with a new architecture that solves the problems at their root.

Both sound reasonable. Both have supporters on the team. And both could be the right decision or a costly mistake, depending on the circumstances. The problem is that many times the choice is made based on intuition, frustration, or pressure, rather than analysis.

This article isn't going to tell you which one to choose. It's going to give you the criteria so that the decision is yours, but an informed one.

What does each thing mean?

It's best to start with the basics, because these terms are used ambiguously.

Refactoring is changing the internal structure of the code without changing what it does. The user doesn't notice anything. What changes is how it's organized internally: more readable, more maintainable, easier to extend. It's done incrementally, on top of the existing system.

Rewriting involves discarding the existing codebase and building a new one from scratch that performs the same functions (and typically incorporates improvements). It's a project in itself, with its own timeline, budget, and team.

Between these two extremes lies a spectrum. It's not always "one thing or the other." But understanding the underlying differences helps in making better decisions.

The signs that open the debate

No one considers rewriting a system that works well. The debate arises when the problems are real. These are the most common signs:

Development time has multiplied. What used to take days now takes weeks. Not because the team is worse, but because each change requires understanding and navigating layers of accumulated complexity.

Bugs are unpredictable. You touch one module and another breaks. Dependencies between components are so opaque that no one can anticipate the effect of a change.

The underlying technology is obsolete. The framework is no longer supported, the language doesn't receive security updates, or the architecture prevents the business from doing things it needs (horizontal scaling, integrations with modern APIs, continuous deployment).

Onboarding is a never-ending process. New developers take months to become productive. There's too much implicit knowledge, insufficient documentation, and many "traps" that only veterans know about.

The team is demoralized. Good developers don't want to work with code that frustrates them. If you're losing talent because the technical stack is a burden, the cost is no longer just technical.

If you recognize several of these signs, you have a real problem. The question is, what solution fits?

When to refactor

Refactoring is almost always the safest option. Not because it's the best in every case, but because the risk is much lower. You're working on a system that already works, with real users and a known history of behavior.

The system does what it's supposed to, but it's expensive to maintain. If the problem is the internal quality of the code—excessive coupling, lack of tests, confusing names, overly large modules—but the functionality is correct and the technology is viable, then refactoring is the logical solution.

The problems are localized. The entire system isn't a disaster. Some areas work well, and some don't. You can address the problem areas without affecting the rest.

You can't stop the product. If the business depends on the system continuing to function and evolve while being improved, a parallel rewrite might not be feasible. Refactoring allows for improvements without halting product development.

The team knows the system. Refactoring requires a thorough understanding of the existing structure. If the original team is still there and understands the decisions made and why, they have the necessary context to improve without disrupting the system.

The budget or timeframe is limited. Refactoring is incremental. You can dedicate 20% of the sprint to technical improvements and achieve gradual results. A complete rewrite requires a concentrated investment and a long-term commitment.

When to rewrite

Rewriting is the riskiest option, but sometimes it's the only one that truly solves the problem. There are situations where trying to improve what's there is just putting patches on a structure that can't stand.

Technology is a dead end. If the framework lacks support, the language is declining, the database doesn't scale, or the architecture doesn't support the business's needs, no amount of refactoring will solve it. Changing the foundation requires rebuilding from scratch.

The cost of maintenance exceeds the cost of construction. If each new feature costs three times more than it should and each fix introduces two new bugs, maintaining the existing system can be more expensive than starting from scratch. But we need to do the real calculations, not the optimistic ones.

The requirements have changed radically. The system was designed for a business model that no longer exists. What was a website for 100 users now needs to serve 100,000. What was a monolith now needs to be a platform with APIs. If the gap between what the system is and what it needs to be is too large, adapting it can be more expensive than rebuilding it.

Security is irretrievable. If the system has structural vulnerabilities that cannot be patched without rebuilding it from the ground up, rewriting ceases to be an option and becomes a necessity.

The questions you should ask yourself

Beyond the signs and criteria, there is a set of specific questions that will help you make the decision:

How much of the system is salvageable? If 70% of the code is sound and the problem lies in 30%, refactor. If 70% is problematic, the balance starts to tip towards rewriting.

Can you precisely define what the new system should do? A rewrite without clear requirements is a recipe for disaster. If you can't specify what the new system should do better than the current one, you're not ready to rewrite.

How long can you survive with the current system? If the system can withstand another 12-18 months with incremental improvements, you have room to refactor. If it's at its limit and any traffic spike or regulatory change could break it, the urgency is much greater.

What happens to the product in the meantime? A rewrite can take 12, 18, or 24 months. During that time, the current product is frozen or progresses at a snail's pace. Can your business afford that? Will your competitors wait?

Do you have the team to do it? A rewrite requires experienced developers who understand both the current system and the target architecture. If you don't have that team, outsourcing a complete rewrite is a very high-risk gamble.

The third way: the strangler fig

There is an option that is often overlooked and that combines the best of both approaches: progressive migration, also known as the strangler fig pattern .

The name comes from the strangler fig, a plant that grows around an existing tree until it completely replaces it. In software, the idea is the same: you build new components around the existing system, gradually connecting them, and over time, the new system replaces the old one without a major outage.

In practice, it works like this: you identify a module or functionality of the current system, rebuild it with the new technology as a standalone service, and redirect traffic or calls to the new component. The old system continues to function for everything else. You repeat the process module by module.

The advantages are clear. You don't have to stop the product. Each new component can be tested and deployed independently. If something fails, it only affects the migrated part, not the entire system. And the team doesn't have to maintain two complete systems in parallel for months.

It's not a silver bullet. It requires a well-defined boundary between modules and works best in systems with some modularity (or where a routing layer can be introduced). But for many projects, it's the most pragmatic option.

The most common mistakes when deciding

Deciding out of frustration. "I'm fed up with this code, let's rewrite it" isn't analysis: it's emotion. Rewrites motivated by frustration often underestimate the complexity of the current system and overestimate how easy the new one will be.

Underestimating what the current code "knows." Every line of code in production contains decisions, bug fixes, and edge cases discovered over time. Rewriting means rediscovering all of that. If you don't take it into account, the new system will repeat the same mistakes.

Not involving the business. The decision to refactor or rewrite isn't just technical. It has implications for timelines, budget, features, and risk. If the technical team decides alone, they might choose the technically elegant but business-unfeasible option.

Compare the current system to the ideal new system. It's easy for the rewrite to win when you compare it to the perfect version you have in your head. But that version doesn't exist. Compare the current system to what you can realistically build with the resources and time you have.

Failing to define success criteria before starting. How will you know if the refactoring has worked? How will you measure whether the rewrite has achieved its goal? Without concrete metrics—average feature development time, number of issues per month, onboarding time—you can't evaluate whether the decision was correct.

A framework for deciding

If you need a quick guide, here are the questions in order:

Does the underlying technology have a future? If not, rewrite it (or migrate it gradually). If so, continue.

Are the problems localized or systemic? If they're localized, refactor. If they're systemic, keep going.

Can you clearly define the requirements for the new system? If not, you're not ready to rewrite. Refactor while you clarify. If so, continue.

Do you have the team, budget, and time for a rewrite? If not, refactor. If so, consider the Strangler Fig before the Big Bang.

It's not a perfect algorithm, but it forces you to answer uncomfortable questions before making a decision. And that, in itself, improves the outcome.

What really matters

The worst decision isn't choosing to refactor when rewriting was necessary, nor rewriting when refactoring would have sufficed. The worst decision is not deciding at all. It's continuing to drag along a system that hinders the team, frustrates the business, and accumulates risk with each passing day.

If your roadmap has been clashing with technical realities for months, the problem won't solve itself. Analyze, decide, and act. And if you're unsure which option is best, find someone who's been through this before. The experience of someone who has seen both options work (and fail) is worth more than any theoretical framework.