Book a call
  1. Blog
  2. Vibe Coding Rescue
  3. Rewrite or refactor, and how I actually decide

Rewrite or refactor, and how I actually decide

Founders with messy, AI-built or inherited code keep asking me if they should start over. Here is the honest process I use to choose between a refactor, a full rewrite, and the module by module path in between.

Poster reading Don't rewrite yet, next to a gateway.js card that routes rebuilt endpoints to new code and everything else to the old app

At least once a week a founder sends me a repo and the same question. “Be honest. Should we just rewrite this thing?” Sometimes the code came from an agency that disappeared. More and more often it came from an AI tool, a weekend, and a lot of optimism. Either way, the app is live, a few customers depend on it, and every new feature breaks two old ones.

I get why “rewrite” sounds attractive. A clean repo feels like a fresh start. But I have watched enough rewrites drag on while the old system kept collecting bugs that I don’t say yes quickly anymore. I also don’t say no by reflex. Here is how I actually decide.

First, what are we even choosing between

A refactor means you keep the running system and improve it in place. Same app, same deploy, same database, better insides. You change it in small steps and ship each step.

A rewrite means you build a new system next to the old one and switch over at some point. New repo, often a new data model, sometimes a new stack. Nothing ships to users until the new thing is ready to replace the old thing.

That second part is the real difference. A refactor gives you value every week. A big rewrite gives you nothing until the cutover, and the cutover date has a habit of moving.

Signs you should refactor

Most messy codebases I see should be refactored, not rewritten. The signs are usually there if you look past the ugly code:

  • The product works. Users can sign up, pay, and do the main thing without calling you.
  • You have real users, and their data matters. Every one of them is a migration risk in a rewrite.
  • The data model is mostly right. Tables or collections match the business, even if the code around them is a mess.
  • The screens are right. Customers like the flows, and the problems are behind the UI, not in it.
  • The pain is local. Two or three files cause most of the bugs, and the rest is just untidy.

If most of that is true, the code is ugly but the system is sound. Ugly code can be fixed one function at a time. I would start with tests around the money paths, then pull the worst file apart, then the next one.

Signs a rewrite is actually justified

Sometimes a rewrite really is the right call. I look for problems at the foundation, not on the surface:

  • There is no structure at all. Business logic lives in click handlers, the same query is copied into twenty places, and there is no seam where you could even start.
  • The data model is wrong at the core. For example, a single user record that also acts as the company, or orders with no real link to the customer. Every feature has to fight this.
  • The foundations are unsafe. Secrets in the frontend, no real authorization checks, a database open to the internet. You can patch some of this, but when it is everywhere, patching becomes a rewrite anyway.
  • The stack is a dead end for what you need, and you can say exactly why in one sentence.

Notice what is not on the list: “the code is ugly”, “the last developer used a framework I don’t like”, or “it would be faster to start over”. That last one is said on almost every project, and it is rarely true, because the old code holds years of small fixes nobody wrote down.

The path in between, which is usually the answer

When I see rewrite signals, I still almost never recommend a big bang rewrite. I recommend rebuilding module by module behind the same API. Martin Fowler named this the strangler fig pattern, after the plant that slowly grows around a tree until it replaces it.

In practice it looks like this. You put a thin routing layer in front of the old app. Every request still goes to the old system by default. Then you rebuild one area, say invoices, properly, with the right data model and tests, and route only those paths to the new code:

// gateway.js: old app stays the default
const app = express();

app.use('/api/invoices', newInvoices);   // rebuilt, live
app.use('/api/orders',   newOrders);     // rebuilt, live

// everything else still goes to the old code
app.use('/api', proxy(LEGACY_URL));

Users don’t notice anything, because the API looks the same. You ship real improvements every couple of weeks. If the new invoices module misbehaves, you change one line and send traffic back to the old one. And at some point the last route moves over and you switch the old app off quietly. No launch day drama.

The hard part is usually the data. If the old and new modules need the same tables, you either share the database for a while or sync between them. I prefer sharing at first and splitting later, because sync code is a bug farm.

What each option really costs

I won’t give you numbers, because they depend completely on your app. But the shape of the cost is predictable.

OptionTime costMain risk
RefactorSpread out, and features keep shipping alongsideLowest. Each change is small and reversible
Module by module rebuildMedium, paid in slices you can stop at any pointData sharing between old and new parts
Big bang rewriteAll up front, with no user value until cutoverHighest. Missed edge cases, a frozen roadmap, a risky switch day

There is also a hidden cost in the big rewrite: while it is happening, the old system still needs fixes. So your team maintains two products and ships improvements in neither. Founders tend to forget this when they draw the plan.

My short decision checklist

Before I give an answer, I go through these questions with the team:

  1. Does the product work for real users today?
  2. Is the data model right, or at least close?
  3. Are the security problems local, or everywhere?
  4. Can I find one seam, a single module, I could rebuild behind the same API?
  5. Can the business survive a period with no new features?
  6. Can someone write down, in one paragraph, what the rewrite fixes that a refactor can’t?

Yes to the first two means refactor. No to the second or third, with yes to the fourth, means rebuild module by module. A big bang rewrite only makes sense when you can’t find any seam, the business can wait, and that one paragraph is convincing to someone who is not an engineer.

One thing that matters either way

Whatever you choose, somebody has to own the result. A rewrite done by an AI tool in a weekend gives you the same problem you started with, just newer. I wrote about that in The AI wrote it, so who is going to maintain it, and the same rule applies here: every line that ships needs a person who can explain it.

If you are staring at a codebase and can’t tell which side of this line you are on, that is a big part of what we do in our vibe coding rescue work. Usually the first step is just an honest read of the code before anyone touches it. You can reach us at contact@broadifitech.com.

And if you decide on your own, that is fine too. Just decide on purpose, with the checklist in front of you, and not because a fresh repo feels nice on a bad day.

Sunil Kr. Samanta

Co-Founder & CTO at Broadifi Tech. Weaving together technology and inner exploration. Built and scaled startups while diving deep into consciousness studies. Equally at home discussing system design or Swami Vivekananda. Currently focused on creating tech that elevates humanity.

Everything by Sunil Kr. Samanta

Start the thread

Your email address will not be published. Required fields are marked *