Your application is five years old. It works, but the smallest new feature takes three times longer than it used to. The developers who built it are gone. The stack is outdated. And one day, someone on the team drops the fateful line: "We should just rewrite the whole thing."
This is a turning point. The decision that follows will shape months of work, a significant budget, and the continuity of your business. Rewriting from scratch promises a fresh start, but the risks are real. Modernizing step by step seems safer, but is it always enough?
Let's be upfront: in most cases we encounter, a full rewrite is a mistake. But not always. This article gives you the criteria to figure out which camp you're in.
The temptation of a full rewrite 🔥
How you get there
A full rewrite is born from accumulated frustration. The code has become a plate of spaghetti. One fix introduces two new bugs. Developers spend more time working around the existing code than building anything useful. Technical debt has piled up over the years, and one day, the system cracks.
The warning signs are usually the same:
- Development times have tripled in two years
- Nobody understands certain parts of the code anymore
- Production incidents are becoming more frequent
- Hiring is hard because the stack scares candidates away
- Simple business requests turn into multi-week projects
The seductive promises
"We'll start on solid foundations." "We'll pick a modern stack." "Six months and it's done." These phrases come up in every rewrite kickoff meeting. And they're sincere. The problem is that they systematically underestimate the complexity of what already exists.
An application that's been in production for five years contains hundreds of business rules. Some are documented. Many are buried in the code, the result of successive patches handling edge cases that nobody remembers. Rewriting means rediscovering each of these rules, one by one.
The "second system effect"
Frederick Brooks described it in The Mythical Man-Month: the second version of a system tends to be over-engineered. The team, freed from the constraints of the old code, wants to improve everything at once. Abstractions are added, future needs are anticipated, a "perfect architecture" is designed. The project balloons. Six months become twelve, then eighteen.
Meanwhile, the old application keeps running. It receives emergency patches that widen the gap with the new version. When the rewrite is finally ready, it covers only 70% of existing features. The business team discovers regressions. Migration drags on. The initial budget has doubled.
This scenario isn't an extreme case. It's the most common outcome of full rewrites.
When a rewrite is actually justified
Despite these risks, there are situations where rewriting is the only reasonable option:
- The stack is dead: the language or framework is no longer maintained, security vulnerabilities go unpatched, impossible to hire
- The architecture is incompatible with new requirements (moving from a rigid monolith to a distributed application, for example)
- The volume of technical debt exceeds the value of the code: maintaining the existing system costs more than rebuilding
- The functional scope has changed radically: today's application has little in common with what was originally built
Progressive modernization: what it actually means 🔧
The principle
Progressive modernization means replacing engine parts without stopping the car. The application keeps running in production while you improve its architecture, code quality, and performance, module by module.
The idea: you improve one piece, verify nothing broke, move on to the next. No big bang. No migration date that gets pushed back three times before quietly disappearing from the calendar.
The approaches
The Strangler Fig Pattern. Named after the strangler fig tree that grows around an existing tree until it replaces it. You build new features in a new system and progressively redirect traffic from the old one to the new one. The old system shrinks until it disappears.
Incremental refactoring. You stay in the same codebase but restructure existing code in small batches. Extract classes, break down overly long functions, introduce unit tests to secure changes. One commit at a time, without breaking what's already running.
Module-by-module migration. You identify the most problematic modules and replace them one at a time. The billing module is unmanageable? You rewrite it in isolation, connect it to the rest via an API, and move on to the next one.
The prerequisites
Progressive modernization only works if certain conditions are met:
- Tests: without a safety net, any change is a gamble. Start by adding tests on critical paths before touching any code.
- Minimum documentation: key business rules need to be identified. No need for a 200-page document, but the main flows must be understood.
- A working CI/CD pipeline: you need to deploy regularly and confidently. Without that, you'll pile up work "waiting for release" and lose all momentum.
- Team buy-in: progressive modernization requires discipline. The team needs to accept that part of every sprint goes toward improving the existing codebase, not just shipping new features.
When progressive modernization is the right choice
- The application works and generates value, even if it's painful to maintain
- The budget doesn't allow halting feature development for 12 months
- Business rules are complex and poorly documented (rediscovering them would take too long)
- The current team knows the existing stack well
- Risk tolerance is low (regulated industry, critical application)
7 criteria to make your decision 📊
We use this table internally when auditing an application. For each row, see which side your situation leans toward.
| # | Criterion | Points toward rewrite | Points toward modernization |
|---|---|---|---|
| 1 | Code quality | Unreadable, unstructured, no conventions | Structured but aging, conventions followed |
| 2 | Test coverage | No tests, impossible to add them | Existing tests or easy to add |
| 3 | Business documentation | Business rules well-known by the team | Rules buried in code, nobody knows everything |
| 4 | Stack skills | Impossible to hire, stack abandoned | Developers available, stack still maintained |
| 5 | Risk tolerance | Can afford a service interruption | Critical application, zero tolerance for downtime |
| 6 | Budget and timeline | Budget available for 12-18 months of rewrite | Constrained budget, need quick results |
| 7 | Business complexity | Functional scope simple and well understood | Complex domain, many edge cases |
How to read this table. If most of your answers fall in the left column, a rewrite is worth considering. If they fall on the right, progressive modernization is the safer bet. In practice, you'll have answers on both sides, and that's normal. What matters is identifying the deal-breakers.
Criterion 3 (business documentation) is often the most underestimated. If business rules are only known through the existing code, a rewrite means rediscovering them blindly. That's the most dangerous scenario.
Four real-world scenarios 🎯
Scenario 1: the post-MVP startup with offshore code
We see this one regularly. A startup has its MVP built by an offshore team to validate the market. The product finds its first customers. Good news. Except the code wasn't built to last: no tests, no documentation, fragile monolithic architecture.
In this case, the functional scope is still limited (it's an MVP), so the cost of a rewrite stays reasonable. You keep what works (database, some components), rewrite the rest with a clean architecture, and add tests from day one. Expect 2 to 4 months.
Scenario 2: the SME with an aging ERP
A manufacturing SME uses a custom-built ERP developed eight years ago in PHP 5. Orders, invoicing, inventory, production scheduling. Three people use it daily. The developer who built it left years ago.
The application is slow, the UI is dated, but the business rules are correctly implemented. And that's the key point: nobody could rewrite those rules from memory. Launching a 12-month rewrite with two systems running in parallel is asking for trouble.
Better to migrate from PHP 5 to PHP 8 in stages, redesign the UI module by module, add automated tests along the way. In 12-18 months, the application is transformed without ever putting production at risk.
Scenario 3: the public agency whose developer left
This one is the most stressful for the client. A local government agency, a citizen request management application, a single developer who left without any documentation. The application runs. Nobody knows how. The smallest bug triggers a crisis.
Here, the "rewrite or modernize" question is premature. First, you need to understand what you're working with. Technical audit, critical flow documentation, tests on the main user paths. That takes 2-3 months. Only then can you decide which modules to modernize and which to rewrite.
Scenario 4: the critical application in production
B2B SaaS platform, 500 active customers, committed SLAs, 99.9% uptime expected. The monolithic architecture is hitting performance limits and a team of 8 developers keeps stepping on each other's toes in the same codebase.
Stopping production is impossible. You can't tell customers "come back in six months." This is the classic Strangler Fig use case: identify high-traffic modules (public API, search engine, dashboard), rebuild them as independent services, and redirect traffic progressively. The old monolith shrinks sprint by sprint. It takes time (18-24 months for a complete migration), but it's the only path that doesn't put the business at risk.
The hybrid approach: the best of both worlds 🧩
In practice, the answer is rarely 100% rewrite or 100% modernization. The most successful projects combine both approaches depending on the module.
The three-step strategy
First, stabilize. Before anything else, secure the existing system. Add tests on critical paths, set up monitoring, document essential business rules. This phase lasts 1 to 3 months and reduces incidents right away. It's also the phase that reassures everyone: management sees things moving, the engineering team regains confidence.
Then, modernize. Once the application is stable, tackle the most problematic modules. Refactoring, dependency updates, performance improvements. Sprint by sprint, the codebase gets younger.
Finally, replace what needs replacing. Some modules are beyond saving. For those, and only those, a targeted rewrite is justified. But by this point, you have tests, you have documentation, you know exactly what the module does. The rewrite happens in a controlled environment. Nothing like a "throw it all away and start over."
The technical audit as a starting point
We tell every prospect who calls us wanting to "rewrite everything": start with an audit. A technical audit gives you a factual snapshot of the code's condition. Quality, technical debt, test coverage, security risks, outdated dependencies. It takes a few days, and it prevents months of work in the wrong direction.
The action plan is built from this assessment. Not before.
Where to start 🚀
Step 1: the technical audit
A serious audit produces a concrete deliverable:
- Application mapping: modules, dependencies, data flows
- Technical debt assessment: scoring by module, identification of critical points
- Security analysis: known vulnerabilities, outdated dependencies
- Prioritized recommendations: what to address first, what can wait
This isn't a theoretical document that ends up in a drawer. It's a roadmap.
Step 2: the prioritized action plan
Based on the audit, you define what to tackle first, with which approach (refactoring, rewrite, migration), for what budget and timeline. The kind of document a CTO can bring to a board meeting with a clear answer to: "How much does it cost, and what do we get when?"
Step 3: early quick wins
Security updates, fixing the most visible bugs, improving load times. Low-risk interventions that produce results in weeks, not months. This is what maintains confidence across the organization while the heavy lifting happens behind the scenes.
Let's be honest: most full rewrite projects that come across our desk don't actually need one. Frustration pushes people toward throwing everything away, but the real problem is rarely the entire codebase. It's usually two or three modules that make everyone's life miserable, while the rest does its job just fine.
The worst decision is no decision. Letting the application degrade while hoping it holds together.
If your application is showing signs of fatigue, start by looking at what you actually have. A technical audit, a few days of work, and you'll know exactly where you stand and where to begin. Let's talk.




