What counts as legacy software?
“Legacy” doesn’t mean old. A ten-year-old system that is secure, documented and easy to change isn’t a problem. Software becomes legacy when it is hard to change, hard to support or risky to run. Common examples we see:
- PHP applications on unsupported versions, often written by one developer years ago.
- Desktop applications in Visual Basic, Delphi or old .NET, installed on office PCs.
- Microsoft Access databases that grew into core business systems.
- Excel workbooks with macros that run invoicing, stock or payroll.
- On-premise ERPs or custom systems with no API and slow reports.
When is modernization worth it?
Modernization is worth it when the cost of standing still exceeds the cost of change. Use this table to judge:
| Signal | Risk if ignored | Urgency |
|---|---|---|
| Unsupported runtime or framework | Security vulnerabilities, compliance issues | High |
| Only one person understands the code | Business continuity risk | High |
| Regulatory change needs data the system can’t store (e.g. e-invoicing) | Non-compliance | High |
| Reports and screens getting slower | Lost productivity, month-end delays | Medium |
| No API or integration options | Can’t automate, can’t connect new tools | Medium |
| Office-only or desktop-only access | No remote work, no mobile use | Medium |
| Spreadsheet workarounds multiplying | Errors, duplicated effort | Medium |
The six modernization approaches
From lightest to heaviest:
- Tune. Fix slow queries, add indexes, cache results, redesign ETL jobs. Fast wins without changing architecture.
- Secure and re-host. Upgrade runtimes, add HTTPS and proper authentication, move to managed cloud hosting with backups.
- Wrap with an API. Add a secure API over the existing database or logic, so new tools (e-invoicing, WhatsApp, BI, mobile apps) can connect without touching the core.
- Re-platform. Move to a modern runtime or database (for example to PostgreSQL) with limited code changes.
- Phased rebuild. Replace modules one at a time on a modern stack, using the strangler pattern.
- Replace with a product. When an off-the-shelf product fits well, migrate to it and retire the custom system.
The right answer is often a combination, for example tune and wrap now, rebuild in phases over the next year.
Why big-bang rewrites fail
The temptation is to rewrite everything and switch over one weekend. It often goes wrong because:
- Hidden business rules live in the old code and only surface after go-live.
- The old system keeps changing while the new one is built, so the target moves.
- Value arrives late: nothing is usable until everything is done.
- Cut-over risk is concentrated into one high-stakes event.
A phased approach spreads the risk. You put a new foundation beside the old system, move one module at a time, and keep both running until each part is proven.
How a phased modernization works
- Discovery. Read the code and database, interview users, map integrations and recover business rules. Write it down.
- Foundation. Set up the new stack, authentication, deployment pipeline and an API that can read and write the existing data.
- First module. Choose a module with high value and contained risk. Build it, run it alongside the old one, and switch users over.
- Repeat. Move module by module, retiring old screens as each new one goes live.
- Data migration. When the new system owns most functionality, migrate remaining data with reconciliation.
- Decommission. Switch off the old system and keep a read-only archive.
Zero-loss data migration
Data is the part of modernization the business cares about most. Our rules:
- Script everything. No manual copy-paste. Migrations must be repeatable.
- Run it many times. Rehearse on copies of production until runs are clean and predictable.
- Reconcile. Compare record counts, financial balances, open items and key totals between old and new. Produce a report the business signs.
- Clean on the way. Fix duplicates and invalid data during migration, with a log of what changed.
- Keep the old data accessible read-only for audit and reference.
Choosing a modern stack
Choose for maintainability, not fashion. For business systems we commonly use:
- Back end: Python with FastAPI, or Node.js, with clean API design and automated tests.
- Database: PostgreSQL, a reliable, open-source database with strong data integrity.
- Front end: a responsive web interface that works on desktops and phones.
- Hosting: managed cloud or your own servers, with backups, monitoring and HTTPS.
Decision checklist
- We know which business processes depend on the system and who uses it.
- We have identified the top three problems (security, speed, integration, access).
- We have tried or ruled out lighter options (tuning, API layer).
- The business rules are documented, or there is a plan to recover them.
- We have a phased plan where each phase delivers usable software.
- Data migration includes reconciliation and sign-off.
- There is a rollback plan for each cut-over.
- Ownership of the new system (code, hosting, support) is clear.
Keeping the team on board
Modernization projects fail as often for human reasons as technical ones. The people who use the old system every day know its quirks, workarounds and unwritten rules better than anyone. Bring them in early:
- Involve power users in discovery. Ask them to walk through a real day. The undocumented steps they mention are the business rules you must not lose.
- Show work early and often. Short demos of real screens with real data build confidence and surface problems while they are cheap to fix.
- Keep familiar where it helps. A new interface does not have to change every habit. Keep field order, shortcuts or report layouts people rely on, unless there is a reason not to.
- Train before cut-over, not after. Short, role-specific sessions and a one-page guide work better than a long manual.
- Name a champion in each team. Someone who tests early, answers colleagues’ questions and feeds back issues.
When users feel the new system was built with them rather than imposed on them, adoption follows and the old system can be retired on schedule.
Budgeting and timelines
Modernization budgets go wrong when the whole system is estimated at once from a distance. A more reliable approach:
- Pay for discovery first. A short, fixed-price review of the code, data and workflows produces a realistic plan and removes most of the guesswork.
- Price each phase separately. Each phase has a fixed scope and price, and delivers working software. You can pause, re-prioritise or stop between phases.
- Budget for parallel running. Old and new systems run side by side for a while. Plan the hosting and support for both.
- Reserve time for data. Migration and reconciliation usually take longer than building screens. Treat them as their own workstream.
- Plan for after go-live. Training, small fixes and the first round of improvements belong in the plan, not in an afterthought.
As a rough guide to shape, not cost: tuning and API-wrapping work is measured in weeks; a rebuild of a focused application often takes a few months; replacing a large, central system is a phased programme that runs over a longer period, with value delivered at each step.
Modernization and compliance
Regulatory change is a common trigger. When an e-invoicing mandate arrives, an old billing system is often the first casualty. You don’t have to choose between a rushed rewrite and non-compliance: a connector can make the old system compliant now, and modernization can follow on a sensible schedule. See how to integrate e-invoicing with an existing ERP.
How Co-Mate helps
We review your system, recommend the lightest approach that solves the real problem, and modernize in phases with zero data loss. See our legacy software modernization service.