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:
- 1. The specialist tax. The person who can touch it. They are senior, expensive, and increasingly rare — because nobody trains juniors on the stack that is leaving. Every week, a significant fraction of their time goes to this one system. They cannot be promoted, reskilled, or let go without a risk nobody wants to price. This is the single largest cost, and it is invisible on the P&L because it looks like "normal engineering time."
- 2. The workaround tax. Every process in the company has bent itself around the system's limitations. The report it can't produce is produced by a human, in Excel, every month. The customer question it can't answer is answered by email. Each workaround is small. Multiplied by every month, for the people doing it, they are a payroll line item nobody approved.
- 3. The fear tax. No one changes anything, because the system's failure modes are known to be ugly. Change requests pile up. Features that would have taken a week get deferred for a year, not because the business doesn't need them, but because the risk of touching the system is unquantifiable. This is a cost on revenue, and it shows up as "we just don't do that kind of thing anymore."
- 4. The on-call tax. The 2 a.m. batch. The month-end job that "usually" works. The one report that fails on the 31st of the month and requires the one person who knows why. The hours spent are small individually and large over a decade, and they always land on the same person.
- 5. The exit tax. Every new hire, every vendor evaluation, every integration with a modern service gets slowed by the fact that the core system speaks the 2004 dialect: a file share, a flat-file exchange, a stored procedure that has never been read. Modern tools want APIs and databases; the legacy system offers neither. Every integration is a bespoke bridge, and bridges have to be maintained.
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:
- 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."
- 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.
- 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.
- 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.
- 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 talent pool shrinks. VB6, classic ASP, older Access versions — every year there is one fewer person alive who learned that stack as a first language. The specialist tax doesn't just get higher. The pool of people who can pay it gets smaller, which is a single point of failure with a retirement date.
- The rest of the world moves. Banks move to API-based payments. Payment processors deprecate old integrations. Cloud vendors stop supporting old runtimes. The legacy system doesn't change; the things it has to talk to do. Every one of those moves is a custom bridge that has to be built and maintained, and the bridges get harder to build as the other side modernizes further.
- The workarounds fossilize. The Excel fix someone made in 2015 becomes "the way we do it" in 2019. By 2026 it is a company process, with training, with templates, with a person whose job includes it. Workarounds don't stay small. They become part of the org chart.
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 component | Boring modern equivalent | What it gives you |
|---|---|---|
| Access forms / reports | A simple web front-end (or a hosted form service) against a real database | Accessible from any browser, auditable, no file locks |
| The .mdb file on a share | A managed relational database (PostgreSQL or SQL Server) on a managed host | Backups, point-in-time recovery, no "open file" corruption class |
| VB6/VBA business logic | A small service in a maintained language (Python, C#, Node) | Runs anywhere, hireable skill, testable |
| 2 a.m. batch on a desktop | Scheduled job on the same host | Logged, retryable, monitorable |
| The one machine in the corner | A managed host with snapshots and offsite storage | The 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:
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
| Risk | How the strangle pattern addresses it |
|---|---|
| The new system is wrong | Each path is small; wrongness is visible in a week, not a year; the old path is the fallback |
| Business stops during cutover | There is no cutover; paths move one at a time while everything keeps running |
| The team doesn't have time | One path per month fits inside normal work; nothing requires a project team |
| Knowledge is in one person | Each 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" estimate | Stop 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
- "It still works" is a statement about function, not cost. The cost is in labor: the specialist, the workarounds, the deferrals, the on-call hours, the integration tax.
- Find your number in an afternoon: price the specialist tax, count the workarounds, list the deferrals, total the on-call hours. That figure is the real budget line for the legacy system.
- Legacy costs compound — shrinking talent pool, a world that keeps moving, workarounds that fossilize. Modern costs are flat once built. The lines cross; the question is when.
- The modern alternative is deliberately boring: a managed host, a real database, a small service, scheduled jobs. No rewrite culture required.
- Strangle, don't replace: move one path at a time, keep the old system running throughout, and require a full bad month on the new side before decommissioning.
- The pattern is stoppable at every step — which is what makes it affordable for a small company, and why it beats the big bang every time I have seen the two compared.
Where to go next
- Deciding between the four paths (rewrite / modernize / contain / SaaS)? → Retiring a Legacy In-House Application: A 2026 Decision Guide
- The system is VB6/VBA on top of a database? → Retiring a VB6/VBA Application: The 2026 Playbook
- The data is the risk before the code is? → Backing Up Microsoft Access: What Actually Works