Every new CTO wants to rewrite the codebase. I know this because I've been that CTO, and because I've watched dozens of other CTOs make the same mistake. You join a company, look at the code, and think "I would never have built it this way." The urge to rebuild is powerful. It's also usually wrong.
Joel Spolsky called rewrites "the single worst strategic mistake that any software company can make." That was in 2000, and it's still mostly true. But not always. Here's how to tell the difference.
The Replatform Trap
A typical replatforming project follows this arc: the team estimates 6 months. At month 4, they realize the old system had edge cases they didn't account for. At month 8, they've rebuilt 80% of the functionality but the remaining 20% is the hard part. At month 12, they're running both systems in parallel because neither is complete. At month 18, they finally cut over, with a punch list of regressions and missing features that takes another 3 months to clear.
During those 18 months, the company shipped almost no new features. Customers who requested capabilities were told "it's coming in the new platform." Competitors moved forward. Engineers burned out from working on a project that was supposed to be done a year ago.
I've watched this exact sequence play out at multiple companies. The replatform eventually succeeds — the new system is genuinely better — but the opportunity cost was catastrophic.
When Replatforming Is Actually Necessary
The platform is end-of-life. If your application runs on a framework or language version that no longer receives security patches, you have a ticking clock. This isn't about preference — it's about risk. Unpatched vulnerabilities in your application framework are liabilities, and they get worse every month.
The architecture fundamentally cannot support your requirements. Key word: fundamentally. Not "it would be hard" or "it would be slow" but "it is architecturally impossible." If your application is a monolithic desktop app and your business needs a web platform, that's a genuine architectural incompatibility. If your application is a web monolith that's slow and you want it to be faster, that's an optimization problem, not a replatform justification.
The total cost of ownership exceeds replacement cost. If you're spending more on maintaining the current system (developer time fighting the framework, workaround code, production incidents caused by platform limitations) than it would cost to build and maintain a replacement over 3 years, the economics favor replatforming. This analysis must include the opportunity cost of the replatform itself — those engineers can't build features while they're rebuilding infrastructure.
When to Resist
The code is messy but functional. Messy code is not a reason to rewrite. Messy code is a reason to refactor, incrementally, while continuing to deliver features. The codebase didn't get messy overnight and it doesn't need to be cleaned up overnight.
A new technology is exciting. "We should rewrite in Rust" or "Let's move to Go" or "Everything should be serverless" — these are technology preferences, not business requirements. Unless the current technology is preventing you from meeting a specific business need, the current technology is fine.
The new CTO wants their stack. I say this as someone who's been the new CTO: your job is to deliver business outcomes, not to implement your preferred architecture. The best CTOs I've worked with made pragmatic decisions about existing systems, not ideological ones.
You want microservices. As I've written elsewhere, the move from monolith to microservices is almost never a reason to replatform. A well-structured monolith serves most companies well. If you do need to extract services, the strangler fig pattern lets you do it incrementally without a rewrite.
The Strangler Fig Pattern
When replatforming is genuinely necessary, the strangler fig pattern is the safest approach. Named after a tree that grows around its host and eventually replaces it, the pattern works like this: build the new system alongside the old one, migrate one feature or workflow at a time, run both systems in parallel during migration, and decommission the old system only when it's completely replaced.
This approach has three advantages: you ship value continuously (each migrated feature works in the new system immediately), you can stop at any point (if the replatform takes longer than expected, you still have a working system), and you learn as you go (the lessons from migrating feature one make migrating feature ten faster).
The downside: it's harder to implement than a clean rewrite. You need to manage routing between old and new systems, handle data synchronization, and maintain two codebases temporarily. This complexity is real — but it's manageable complexity, unlike the unmanageable risk of a big-bang rewrite that might not work.
Related: You Inherited a Codebase Nobody Understands | Monolith vs. Microservices: The Pragmatic Answer | Tech Debt Translation: Making Your CFO Care