The old code is not the liability
Most “let’s just rewrite it” calls get made by people who never maintained the old system, and never had to put a figure on the new one. Both are tells.
A rewrite feels clean. New stack, no legacy baggage, a chance to finally do it “right”. But the ugly old code is not the liability. The behaviour encoded in it is the asset, and a rewrite deletes that on day one. A manufacturing client ran a fourteen-month “modern rewrite” with a team of nine. It shipped something that did about sixty per cent of the original, slower, and missed the pricing rule for split deliveries that nobody had documented, because it only ever lived in the old code. The business ran on the legacy system the entire time. Figures rounded and anonymised, but real: roughly EUR 1.8M in engineering, plus about EUR 35k a month to run both systems in parallel for over a year.
That is the failure mode, and I am not neutral about it: careful incremental modernisation is also what I sell. I am telling you anyway, because the rewrites I have watched fail did not fail on architecture. They failed on a number nobody calculated before kickoff.
The three cases where a rewrite earns its money
So set the bias aside and be affirmative. A rewrite is the right call in exactly three cases, and if you pass one of them, you rewrite.
The platform is genuinely dead. Unsupported runtime, no patches, nobody left who can compile it, or a live security liability you cannot carry. The floor is gone. You are not choosing.
The domain changed. The old system models a business that no longer exists. You are replacing logic, not porting it, because the logic itself is what became wrong.
You can carve a seam. Rewrite one bounded piece behind a stable interface, run both, cut over when it proves itself. Strangler, not big bang. This is the case most systems are actually in, and it is the one the build-versus-buy-versus-modernise decision usually resolves to.
Fail all three and the arithmetic tends to kill the rewrite on its own: two teams running in parallel for eighteen to twenty-four months while you rediscover the forty edge cases nobody documented, against phased modernisation at a known monthly burn.
The caveat nobody puts on the slide
That third case (carve a seam) has a caveat the deck skips. If the seam sits in the wrong place, the strangler becomes its own decade-long liability. The boundary is the entire bet. Draw it wrong and you own two systems forever.
The most common way to draw it wrong is a shared database. If a shared database is the real coupling, the strangler stalls. You cannot split services while they all write the same tables, so you strangle the data model first, not the code. Skip that and you ship a distributed monolith: the same coupling, now over the network, slower, and harder to roll back. If you cannot carve the data, you may be closer to the three-case test, and to a genuine rewrite, than you hoped.
The traps that dress up as rewrites
It is a trap to rewrite when the real reason is “this code is hard to read”. That is a refactor, not a rewrite. It is a trap when there are no tests, because then you have no definition of done. And it is a trap when the people estimating it have never operated the thing at three in the morning.
Before you write the business case, run the three-case test. If the platform is alive, the domain still holds, and you cannot cleanly carve a seam, the honest answer is usually to modernise in place and spread the cost across shipped value rather than betting the company on one launch date. If you are weighing a rewrite and want a second read on which case you are genuinely in, talk to TrueForge before the number gets locked.