
Sean Weldon
October 8, 2026
10
min. read
and updated on:
October 14, 2026
Legacy software is not software that is old. It is software that is difficult to change, and the two are not the same. A ten-year-old system with tests, documentation, and a sane architecture is...

Legacy software is not software that is old. It is software that is difficult to change, and the two are not the same. A ten-year-old system with tests, documentation, and a sane architecture is not legacy. A three-year-old system nobody dares modify is.
That distinction matters because it identifies what you are actually solving. Modernisation projects that begin from age rather than from difficulty tend to replace working software with newer software that is equally hard to change.
Five distinct problems get described as legacy, and each has a different remedy.
Nobody can change it safely. No tests, no documentation, original author gone, and every change breaks something unrelated. This is the practical definition and the most common.
The technology is unsupportable. An abandoned framework, a language version past end of life, or a dependency with no maintained successor. This is a genuine forcing function with a deadline attached.
It cannot do what you now need. Single-tenant where you need multi-tenant, no API where you need integration, no mobile where the work happens in the field. An architectural mismatch rather than a quality problem.
It costs too much to run. On-premise hardware, per-seat licensing on a platform you have outgrown, or infrastructure that scales badly.
It is a compliance liability. No audit logging, weak access control, unencrypted data, and an enterprise customer or regulator about to notice.
Write down which of the five applies. Projects that skip this step tend to rebuild the interface, which is the visible part, while leaving the actual problem in place.
The modernisation decision is routinely made by whoever is in the room. The developer who inherited the code says rebuild, because unfamiliar code always looks worse than code you wrote. The firm quoting the rebuild agrees, because a rebuild is a larger engagement than a refactor.
A code audit replaces that with evidence: architecture assessment, test coverage, security findings, dependency currency, and, most importantly, whether the existing codebase can support your actual roadmap. It costs $5,000 to $25,000 over one to three weeks against a decision that routinely involves six figures.
Bolder Apps sells code audits as a standalone engagement, and the practical guidance for any firm you use is to require that the report includes remediation effort estimates and stated reasoning, so the recommendation can be interrogated and taken to other bidders rather than simply accepted.
| Path | What it means | Cost relative to rebuild | Risk |
|---|---|---|---|
| Rehost | Move to modern infrastructure, code unchanged | 10 to 25 percent | Low |
| Refactor | Improve the code in place, behaviour unchanged | 20 to 50 percent | Low to moderate |
| Incremental replacement | Replace piece by piece behind a boundary | 70 to 110 percent | Low, spread over time |
| Full rebuild | New system, cut over | Baseline | High |
Note that rehosting solves cost and supportability problems and solves nothing about changeability. It is frequently a sensible first step that buys time rather than a modernisation in itself.

The approach that gets skipped because it is less satisfying than a clean rebuild: keep the existing system running and replace it in pieces.
A new component takes over one area of functionality. Traffic for that area routes to the new component. The old code for it is retired. Repeat with the next area. The product keeps working throughout, each step delivers value independently, and you can stop when the remaining old system is good enough.
The precondition is a seam you can substitute behind: an API boundary, a service boundary, or a module boundary. If none exists, creating one is the first piece of work rather than a reason to abandon the approach.
What this buys you is optionality. A rebuild requires being right about everything before you start and delivers nothing until cutover. Incremental replacement lets you learn between steps, which matters because your understanding of the requirements will change as you go.
The largest risk in a full rebuild is not cost or duration. It is losing the undocumented business rules the existing system encodes. Years of accumulated edge-case handling is why the old code looks messy, and it is also why it works. Rebuilds fail when the new system is cleaner and does not handle the fourteen exceptions the old one had learned about.
Whichever path you choose, the domain knowledge in the existing system has to be extracted, and it is rarely written down.
Four sources. The code itself, read specifically for conditionals and special cases rather than for structure, since each one usually encodes a real situation somebody encountered. The people who use it, who know which fields matter and which are ignored. Support tickets and change history, which document the problems that shaped it. And the data, where unexpected values and patterns reveal behaviour nobody documented.
Budget real time for this. It is not analysis paralysis, it is the difference between a replacement that works and one that reopens fourteen resolved problems.
Migration is its own project and routinely 10 to 20 percent of a replacement build, and it is absent from almost every initial estimate.
What it involves: mapping old schema to new, which is where you discover fields used for two purposes and dates stored in three formats. Cleaning, because legacy data contains duplicates, orphans, and values that violate their own rules. Validation, comparing record counts and totals before and after. A rehearsal on production-scale data before the real run. And a rollback plan.
Then a parallel-running period where both systems operate and outputs are reconciled. Cutting over on day one with no reconciliation is how a data problem becomes a month of untangling, and in financial or regulated contexts it is how it becomes an audit finding.

An audit is $5,000 to $25,000 over one to three weeks. Targeted refactoring of specific problem areas is 20 to 50 percent of a rebuild cost. Incremental replacement of a mid-sized business system typically runs $120,000 to $350,000 across 9 to 24 months, delivered in pieces. A full rebuild of a comparable system is $100,000 to $300,000 over 6 to 14 months, plus migration and parallel running.
Bolder Apps builds backends in Laravel, Yii2, and Node.js, front ends in React with Ant Design or Material, and mobile in Flutter, FlutterFlow, Swift, and Kotlin, prices project work fixed-scope rather than hourly, and sells discovery and audits as standalone engagements. On modernisation work the scope items worth naming explicitly in any proposal are data migration, the parallel-running period, and rule recovery, because all three are real work and all three are commonly omitted from the estimate that wins the bid.
Modernisation delivered as one large project is the highest-risk version. Sequenced, each step is independently justifiable.
First, stabilise. Add monitoring so you know what is actually failing, get deployment to a repeatable state, and verify that backups restore. None of this is modernisation and all of it makes everything after it safer.
Second, add tests around the areas you intend to change, which is what makes the changes safe rather than hopeful. Comprehensive coverage is not the goal; coverage of the paths you are about to touch is.
Third, create a seam if none exists. An API boundary or service boundary you can substitute behind, which is the precondition for incremental replacement.
Fourth, replace the highest-pain area behind that seam, then the next. Each step ships and each step is independently valuable.
Fifth, stop when the remaining old system is good enough. This step is the one nobody plans and the one that saves the most money, because full replacement is rarely necessary once the painful parts are gone.
Three practices that keep a modernisation from consuming the organisation.
Keep a feature capacity reserve. A modernisation programme that freezes all product work for a year creates commercial pressure that eventually forces a shortcut. Reserve twenty to thirty percent for the roadmap even during heavy replacement work.
Report progress in business terms rather than technical ones. A stakeholder cannot evaluate services migrated. They can evaluate that the reporting that took three days now takes an hour.
Decide in advance what you will not modernise. Explicit exclusions prevent the programme expanding to fill available budget, which is the pattern that turns a two-quarter effort into a permanent one.
Bolder Apps prices project work fixed-scope rather than hourly and sells discovery and code audits as standalone engagements. On modernisation the value of a phased fixed-scope structure is that each phase has a boundary, which is what lets you decide between phases rather than committing to an outcome nobody can yet specify.
Three situations where the honest answer is not yet.
The system works, changes are rare, and the technology is still supported. Modernising software you barely touch is spending money to feel modern.
The business process it supports is about to change. Replacing a system and then discovering the process it encodes is being redesigned means doing the work twice.
You cannot fund it to completion. A half-modernised system, two architectures running in parallel with no plan to finish, is worse than either alternative and is the most common outcome of an underfunded modernisation.
Ask how long a small, well-understood change takes from request to production, and how confident the team is that it will not break something else. If the answer is weeks and not confident, it is legacy regardless of age. If it is days and reasonably confident, it is not.
The backend, in most cases, because the interface is the visible part and the backend is usually the actual constraint. Interface-first modernisation produces a modern-looking product with the same inability to change, and it also frequently paints you into supporting a new interface against an old data model.
Under incremental replacement, yes, and it is one of the approach's main advantages. Under a full rebuild you are effectively running two development efforts, which is why feature work usually freezes and why rebuilds are commercially risky.
Long enough to cover a full business cycle for whatever the system does, which for financial or reporting systems means at least one month-end close and ideally a quarter. Shortening it to save cost is the compression that produces the reconciliation problems.
Underestimating the domain knowledge in the old system, followed by omitting data migration from the budget. Both are addressable during discovery, and both are cheaper to address there than in month eight.




