Sooner or later, the codebase that got you here starts holding you back. Changes take weeks. The features customers keep asking for feel out of reach. Or a security review blocks a deal. Then you have a call to make: patch it, rebuild it piece by piece, or tear it down and start over. Most teams make that call on a gut feeling, and it’s one of the most expensive coin-flips in the business. The video above is the full walkthrough. This is the short written version, for skimming and reference.
The five symptoms that say it’s time
Modernization rarely starts as a plan. It starts as symptoms. The five we run into most often:
- Scalability and performance. The system hits a ceiling. Sales keeps closing clients it physically can’t carry, so you either turn away revenue or crash under the load.
- Operational struggle. It works, but it’s closed off. No clean integrations, no interfaces. Every enterprise you onboard costs a week of engineering just to wire it up to anything.
- Poor architecture and too much complexity. One change breaks five other things, integrations get unreliable, and developers start routing around the system with workarounds. Often the fix is removing complexity: folding ten fragile third-party integrations into code you own, or collapsing three separate front-ends (web, iOS, Android) into one hybrid codebase a smaller team can maintain.
- Weak security. Common in vibe-coded apps. It looks perfect on the surface, but underneath no one can tell you how the data is actually protected. Open or wildcard permissions mean anyone who knows where to look can pull every user’s personal data and wipe the whole database on the way out. That’s not a bug you fix on Monday. That’s the business, gone overnight.
- A limited talent pool. The wrong core technology becomes a hiring handbrake. There are more than twenty times as many JavaScript developers as Elixir ones, so a niche stack chosen because a co-founder happened to know it can stall the whole org the moment you need to grow the team.
Read these as measured, not felt. “The code feels bad” isn’t a diagnosis.
Start with discovery, then measure
Before you pick a path, get honest about two things. First, the system: where it is today versus where it needs to get to. Second, the business: what you’re trying to achieve, and what’s actually in the way. There are always a hundred things wrong with a codebase. An honest discovery separates what blocks the business from what’s just an engineer’s nice-to-have. You fix what stands in the way of the goal, and the rest waits.
Then put real numbers on it. Four things worth measuring:
- Technical health. Response times, error rates, uptime. What your users actually feel.
- Complexity. How many platforms, subsystems, screens, endpoints, and tables. The more moving parts, the more every change costs you.
- Quality. Test coverage, security posture, how bad the debt is, whether the architecture can still hold up.
- Business value. Time-to-market, cost to maintain, and the one everyone skips: which parts of the product people actually use. That last one tells you what’s worth carrying forward and what’s just dead weight you can drop.
Now you’re not guessing. You’re choosing on evidence.
The four paths
Most people frame this as a choice between rewriting and leaving it alone. There are four options, and they line up like a ladder, from doing the least to doing the most:
- Continue as is. Keep shipping on the system exactly as it stands. This fits only when the pain is low and nothing on the horizon needs more from it. The honest risk is that this is usually drift dressed up as a decision. And even if you stay put, don’t deepen the debt. Hold every new feature to a higher standard, with its own tests, so the old debt stops growing and the parts you touch most often start getting better on their own.
- Stabilize. Keep the system and clean it up gradually, to an acceptable shape rather than a perfect one. This is the right call when the bones are sound and the real problem is debt, coverage, and security drift, not the fundamental architecture. Pin the existing behavior down with tests first, then refactor safely behind them, starting with the lowest-hanging fruit. One healthcare platform we modernized this way went from effectively zero tests to over 95% coverage, moved off its end-of-life stack, and cleared an enterprise security review, all while it kept running. AI did much of the heavy lifting, which is what made catching up that fast affordable.
- Strangle incrementally. Stand a new system up next to the old one and migrate feature by feature until the old one can be switched off. Martin Fowler named this pattern the Strangler Fig. It fits when you need a new shape but the business can’t stop delivering while you get there. A decade-old media platform moving terabytes a month couldn’t go offline, so we built the new platform alongside the original and rolled users over gradually, with no big-bang cutover. Downtime incidents dropped 90%, infrastructure cost dropped 80%, and the business ran the entire time.
- Big-bang. Stop, rebuild, and cut over. It’s the most debated path, and it fits only in a few narrow cases: when the foundation fundamentally can’t carry the promise, when the system is small or early enough that you’re not throwing much away, or when a hard external deadline leaves no room to be gradual. Before you pick it, answer Joel Spolsky’s question honestly. What makes you think you’ll do a better job the second time?
One warning across all four. AI has made the incremental paths cheaper, and it’s even made rewrites more reasonable than they used to be. But the safety doesn’t come from the model. It comes from tests, guardrails, and rolling out in stages. When AI translates old code into new code, it makes mistakes, and it makes them systematically. Only a real test suite catches them.
How to choose: three questions
There’s no scoring grid. Just three questions, asked in order:
- Does the foundation need to change at all? If no, continue as is.
- Can the current foundation carry the promise? If it just needs cleanup and the bones are good, stabilize.
- Can you get there while the system keeps running? If yes, strangle. If you truly have to stop and switch, big-bang.
The whole thing comes down to that third question: the path isn’t set by how bad the code is. It’s set by whether you can change it while it keeps running.
The hard case: the staged conflict
The hard projects have a staged sequence of goals that depend on each other, and not enough resources to modernize even once before the next milestone forces the issue. You win a deal on a patched-together, prototype-grade version. The client lands. Now there’s finally money to do it right. But the bar keeps rising, from “make it demoable” to “make it actually work in production,” while the budget only unlocks after the deal closes. So you owe a better system before you can pay for it.
At bottom, this is a bet about timing. Do you invest ahead, spending to get the system ready before the contract is even signed, and speculate that the deal lands? Or do you win the deal first and take on the risk of catching up on the debt once the resources arrive? Neither is free. One bets your cash, the other bets your delivery. Just make that bet on purpose, not by accident.
It’s a phase, not a destiny
Whichever path you pick, it isn’t forever. The paths sequence. You continue as is until the debt starts to bite, then stabilize, then strangle when the promise needs a new shape, or jump straight to a rebuild when something forces it. Re-run the whole decision at every major milestone. The right answer this quarter isn’t a promise you owe next year.
Why now
Every few years, software has to be redone. That’s just the nature of it. Fifteen years ago everything moved from the desktop to the web. Ten years ago it moved to mobile. The shift now is toward systems that are agentic, ready for AI to operate them, and open enough to plug into everything around them. Each wave left a lot of perfectly good software a generation behind. What’s different this time is the cost. AI has made modernizing and rebuilding genuinely affordable, because work that used to take years now takes months. So decisions that were quietly off the table, like the rewrite, the migration, or the clean architecture you could never justify, are back on it.
But the honest first move is never to pick a path. It’s to measure, so you choose on evidence instead of a gut feeling or a vendor’s pitch. That’s why we tell our clients to start with an audit before they commit to any path: an outside, senior look at what you actually own, what’s breaking, and what to do first, with your own numbers, not ours.