Fix, modernise or replace? A framework for legacy systems

Most legacy conversations start after the third outage in a month, or the fifth developer who has left because nobody could explain how the invoicing module talks to the stock system. By that point somebody in the business has usually already said the word "replace." It becomes the assumed answer before anyone has actually looked at what the system does or what it is costing to leave alone.
We have taken over everything from twenty-year-old VB6 applications to bespoke .NET systems built by a developer who left years before anyone called us. A full rebuild has been the most expensive option on the table in nearly every one of them, and it was rarely the right one. This is the framework we actually work through before recommending a direction, and roughly how often each answer turns out to be the right one.
Measure the cost before you look at the code
Old code is not automatically a problem. Code that nobody can safely change is the problem, and those are different things that get confused constantly. Before deciding anything, get specific. How many hours a month does the team spend working around known bugs instead of fixing them. How many changes get delayed because one person holds all the institutional knowledge. When the system was last patched, and by whom.
If the answer to any of those is genuinely "we don't know," that is the first finding. Most legacy decisions get made on how the code looks rather than what it costs, because measuring the drag takes more discipline than reacting to the latest outage.
Separate the code problem from the knowledge problem
This is where modernisation projects go wrong before they start. A system can have badly written code, no tests, no documentation, dependencies tangled into each other, while still holding years of business logic that works. Pricing rules. Exceptions the business added after a customer complaint nobody quite remembers the reason for anymore. That logic is not in a document anywhere. It is in the code, and often only in the code.
A rebuild throws that away and asks the business to rediscover it, usually in production, usually the expensive way. Modernising in place, refactoring around the logic that works while replacing the parts that are actually broken, keeps that knowledge intact. It reads as less dramatic in a project update than "we're rebuilding it." It is usually faster and considerably less risky, which matters more than how the update reads.
Four questions that actually decide it
Can it still be hosted and patched safely?
If the system depends on an operating system or database version that no longer receives security patches, that is a constraint, not a preference. New vulnerabilities keep turning up in old software, and an unsupported stack has no route to a fix. This tends to outweigh every other factor on the list, because it is the one risk that does not stay static while you decide.
Does the team that understands it still exist?
If the one person who knows why a module behaves the way it does has left, or is about to, that gap gets more expensive to close every month it stays open. This is often the real driver behind a rebuild instinct: not that the system is bad, but that the knowledge of how it works is walking out the door and nobody has written any of it down.
Is the pain technical, or is it wearing a technical costume?
Some "legacy system" complaints are process complaints in disguise. No amount of rebuilding fixes a system that feels slow because three departments each insist on a different approval step before anything moves. Worth asking before committing a budget: would a brand new system running the same process still feel slow in six months?
Can the business absorb the downtime a rebuild implies?
A rebuild is rarely a clean swap. There is a migration period, a parallel-running period, and a stretch where the new system does slightly less than the old one while it catches up. That has to be planned for at the start, not discovered halfway through when the team is already relying on the new system for real work.
When modernising is the right call
Most of what we see fits here. Wrapping legacy components behind modern interfaces, replacing the riskiest parts first, automating what is currently done by hand. It lets a business keep what works, remove the actual risk (unsupported infrastructure, a single point of failure, logic that lives only in one person's head), and spread the cost over months rather than committing a large budget to a rebuild that might take a year just to reach where the old system already was.
Full replacement earns its place when the system is actively fighting the business rather than supporting it: when the platform cannot do what the market now needs regardless of how well it is maintained, or when the cost of keeping it running safely has clearly overtaken the cost of starting again. Those cases exist. They are the minority, not the default.
Common questions
Should I fix, modernise or replace a legacy system?
Start by measuring what the system actually costs you in hours, delayed changes and risk, not how old the code looks. Most systems are worth modernising in place: keep the business logic that works, replace the parts that are genuinely broken. Full replacement earns its place only when the platform itself cannot do what the business now needs, or the system depends on infrastructure nobody can safely patch.
Is a full rebuild usually the right answer for old software?
Rarely. A rebuild throws away years of business logic, pricing rules and edge cases the business added after real problems, and asks the team to rediscover all of it, often in production. Modernising around the parts that work keeps that knowledge intact and is usually cheaper, faster and considerably less risky.
How do I know if a legacy system is actually costing us money?
Measure it directly. How many hours a month go into working around known bugs rather than fixing them. How many changes get delayed because one person holds all the knowledge. When the system was last patched, and by whom. If nobody in the business can answer those questions, that is the first finding, and it usually means the decision has been running on instinct rather than evidence.
What is the risk of running unsupported software?
If the system depends on an operating system, database or framework version that no longer receives security patches, that is a hard constraint rather than a preference. New vulnerabilities keep being found in old software, and an unsupported stack has no route to a fix. That risk tends to outweigh most of the other factors in the decision.
Where to start
If you are looking at a system you inherited, or one that has grown past the point anyone fully understands it, the first useful step is not a rebuild plan. It is a proper audit: what the system actually does, what it is really costing you to leave alone, and which parts are safe to touch without unpicking something nobody remembers building. That is the work we do with clients before recommending a direction, through our legacy software development and support service.
If your own answer to "is this actually a problem" is still unclear, the five questions in is your seven-year-old software a problem? are a faster way to find out than reading a framework like this one. And if the conclusion turns out to be full replacement rather than modernisation, our software and app cost calculator will give you a costed estimate for what that would actually take.