Decision guide ~10 min read By The Compiler Whisperer · October 2026

The Hidden Cost of "It Still Works": What Legacy Systems Really Cost

There is a sentence that ends every conversation about old software: well, it still works. And it is true. The invoicing system from 2004 still produces the invoice. The order app built on VB6 and an Access database still takes the order. The batch job that has run at 2 a.m. for fifteen years still runs at 2 a.m.

"It still works" is a statement about the function. It says nothing about what the system costs you every week to keep it that way. And that cost is real, it is recurring, and it is almost never on any spreadsheet — because no one budgets for it. This article is about finding that number, in your own company, in an afternoon. Not to justify a rewrite. To decide, with a real figure instead of a feeling.

Where the cost actually lives

When people estimate the cost of a legacy system, they usually list the license fees — and there usually aren't any, which is why the system feels free. That is the mistake. A system that "still works" but has no license bill is not free. It is being paid for in something else, in five places, in this order of how hidden they are:

Notice what all five have in common: they are labor costs, not software costs. The software is free. The people who keep it alive are not. That distinction is why "it still works" sounds like an argument for keeping it, when it is actually an argument about what you are paying for.

How to find your number in one afternoon

You do not need a consulting engagement. You need three hours and the two or three people who actually touch the system. Here is the exact exercise I have used to make these costs visible:

  1. List the touch points (30 min). Who logs in, whose laptop runs it, which processes depend on it, which reports come out of it. One line each. You will be surprised by how long the list is — and how much of it nobody thought of as "the legacy system."
  2. Price the specialist tax (15 min). Ask the person who maintains it: roughly what share of their week goes to this system? Multiply that share by their fully-loaded cost. That one number usually exceeds the entire year's budget of the modern tool being discussed as its replacement.
  3. Count the workarounds (45 min). Sit with the operational person who feeds the system and collects its output. Every manual step they take monthly — the Excel fix, the email exchange, the re-keying — gets a line and a minutes-per-month estimate. Multiply by their hourly cost. Annualize.
  4. List the deferrals (30 min). What has been wanted but not built, and why? For each item, one line: what it was, why it died, what it was worth roughly. These are not precise — and they don't need to be. They exist to show the pattern, and the pattern is the story.
  5. Add the on-call hours (15 min). How many times in the last twelve months did the system need a human at an inconvenient time? What did those hours cost, fully loaded? Include the cost of the call, not just the fix.

Sum the five lines. Call it the annual cost of "it still works". Then do the arithmetic you already know how to do: what would it cost to run the same function on modern, boring, well-documented infrastructure, including a realistic migration effort? You do not need a precise number. You need the two numbers to be in the same order of magnitude — because in my experience, once the labor costs are on the table, the modern option is almost always cheaper within two years, and the gap widens every year after, because the legacy side's costs compound with headcount changes while the modern side's costs stay flat.

Why the number gets worse, not better, over time

Three forces make legacy costs rise even when the system "isn't doing anything new":

The practical implication: the cost of keeping a legacy system is not a fixed number you pay, it is a number that grows — while the cost of the modern alternative, once built, is flat or falling. The two lines cross at some point. Finding that point is the whole decision.

The modern alternative, without the hype

When I say "modern," I don't mean microservices, event sourcing, or a stack your team has never touched. For a small or medium business with a legacy line-of-business system, the modern option is deliberately boring:

1990s-era componentBoring modern equivalentWhat it gives you
Access forms / reportsA simple web front-end (or a hosted form service) against a real databaseAccessible from any browser, auditable, no file locks
The .mdb file on a shareA managed relational database (PostgreSQL or SQL Server) on a managed hostBackups, point-in-time recovery, no "open file" corruption class
VB6/VBA business logicA small service in a maintained language (Python, C#, Node)Runs anywhere, hireable skill, testable
2 a.m. batch on a desktopScheduled job on the same hostLogged, retryable, monitorable
The one machine in the cornerA managed host with snapshots and offsite storageThe failure modes become boring: restart, restore, done

Notice that nothing in that table requires a rewrite culture. A managed Windows or Linux host running the same shape of application — a database, a thin front-end, scheduled jobs — is already 80% of the way to "boring modern." If the app is Windows-based, a managed host ↗ is a legitimate first step: the same OS, the same shape, but with snapshots, offsite backups, and support that answers the phone — the infrastructure-level fixes that don't require touching the application at all. Affiliate link — I may earn a commission if you sign up; you pay the same price either way.

And the cloud choice does not need to be a religion. A small system like this runs fine on any of the major clouds, or on a managed host that abstracts the cloud choice away. Pick where your team is most comfortable, because the boring part of modernization is that the boring choice is the right one — the stack that your hireable staff can maintain in ten years matters more than the one that scores highest on a conference benchmark today.

Retiring it incrementally, not in one big bang

The big-bang rewrite is where these projects die, and I want to be explicit about why: it asks you to bet the running business on a system that isn't running yet. For a small team, the failure mode is not "we built the wrong thing." It is "the rewrite took twice as long as estimated, and during that time the old system needed a fix, and the fix went into the old system, and now we have two systems and the new one is wrong."

The pattern that works is the opposite of a rewrite. It is a strangle, not a replace:

Month 0 : Old system running. New host provisioned. Database replicated or exported. Nothing changed in production. Month 1-2 : One report moves to the new side. Read-only against the same data. Both systems produce it. Diff the output. Month 3 : One write path moves (e.g., new invoices only). The old system still owns everything else. Month 4-6 : More paths move, one at a time, each behind its own rollback: if the new path misbehaves, the old path is still there, unmodified. Month 6+ : The old system is now read-only for the paths that moved. It is no longer load-bearing. Decommission on its own schedule, not on a deadline.

Two properties make this pattern safe for a small team. First, every step is independently reversible — no step requires a cutover moment, and there is no cutover moment, which is where these projects actually fail. Second, the old system never stops working, which means the business never stops working, and the pressure to rush — the pressure that produces the bad versions of this work — never builds.

The rule I would not break: never decommission the old system until the new one has been the only system for a full bad month. Month-end, a data glitch, a holiday queue — whatever the worst ordinary week looks like for you. If the new system survives your actual worst week, it is ready. If it didn't, you learned it for free, and the old system is still there. That trade is the whole point of doing it incrementally.

The risks, and how the incremental pattern addresses them

RiskHow the strangle pattern addresses it
The new system is wrongEach path is small; wrongness is visible in a week, not a year; the old path is the fallback
Business stops during cutoverThere is no cutover; paths move one at a time while everything keeps running
The team doesn't have timeOne path per month fits inside normal work; nothing requires a project team
Knowledge is in one personEach moved path gets documented as it moves; the doc is a side-effect of the work, not a separate task
Costs exceed the "hidden cost" estimateStop at any month where the next path isn't worth it; the old system still runs, so stopping is free

That last row is the one people miss. A rewrite is all-or-nothing: if it runs over budget, you have spent the money and the system may not be done. An incremental migration is optional at every step. You can stop after one moved path and still be better off than before, because you have a managed host, a real database backup, and a documented procedure — with the old system still running as it always did. The ability to stop is what makes the whole thing affordable for a small company.

Frequently asked questions

Do we need to move to the cloud at all, or can we keep the old machine?
You can keep the old machine for as long as the machine and the knowledge both survive. The incremental pattern works from on-premises too. The question is not cloud-or-not, it is whether the current arrangement has a plan for the two failure modes that will eventually end it: the machine, and the person.

What if we can't afford to migrate anything this year?
Then do the one thing that costs the least and removes the most risk: get the data out of its single-file state and into something that backs up properly and can be restored, on hardware you can replace without a project. That one step removes the largest catastrophic risk in the whole system, and it does not require touching the application. Everything else can wait a year. That step should not.

Is a rewrite ever the right answer?
Sometimes — when the existing logic has zero value, when the data model is actively harmful, or when the system's limits are blocking revenue so hard that the workaround tax is obvious. For most small-business line-of-business systems, though, the logic is the asset and the code is the accident. Preserve the logic, move the plumbing, and the "rewrite" becomes a series of small, affordable, reversible moves.

Summary

Where to go next

Disclosure: some links above are affiliate links (marked where they appear). They never cost you more, and they never influence the recommendation. Full details on the affiliate disclosure page. This article is general engineering information, not professional advice.