Retiring a VB6/VBA Application: The 2026 Playbook
Somewhere in your company there is an application written in Visual Basic 6. Maybe a macro suite in Excel that runs your month-end close. Maybe a Win32 desktop client on a server that no one has rebooted since 2014. It has survived three office moves, two ERP failures, and every Windows upgrade since.
I wrote these systems in the 1990s and the 2000s. C, C++, MFC, VB6, VB.NET — and I spent the following two decades retiring them for other people. This playbook is what I wish every IT manager had been handed the day they found out who the last VB6 developer was, and that person was leaving next month.
Read this once, then work through it in order. It is written to be done, not read.
Step 1 — Find out what you actually run (most companies fail here)
The first surprise in every VB6 retirement I have touched is that the application nobody remembers is the one doing the work. Before touching a line of code, produce a list:
- Every machine with VB6-era executables. Check the build date on every .exe on the shared drives. A 2003 build date is a confession.
- Every scheduled task. On the server: Task Scheduler, plus the
atjob remnants, plus any .bat files inC:\Windows\System32\that no one wrote there. Legacy apps hide their entry points. - Every Excel macro with a name. Open the VBA editor (Alt+F11), export every module to .bas files. Do this now, while the file still opens. The file that "mostly works" on one machine may be the only copy.
- Every DSN / ODBC connection string. These live in the registry, in .ini files, and in code. Grep the source for
Provider=,Data Source=, andDriver=. Each one points at a database you may not know you have. - Every file path the app writes to. Run it once with Process Monitor (free, from Microsoft) and record every file it creates. That list is your real data inventory — it is usually longer than the one in the documentation, because there is no documentation.
If you cannot complete this list in two weeks, stop. You do not have a retirement project yet; you have a discovery problem, and pretending it is a migration project is how month-end gets lost.
Step 2 — Classify the application honestly
Once you know what it is, every VB6/VBA application falls into one of four shapes. The shape decides the strategy — not your feelings.
| Shape | What it looks like | Strategy |
|---|---|---|
| Form-on-top-of-a-database | Entry screens over Access/SQL Server, reports out | Replace (a SaaS tool does this) or wrap |
| Batch computer | Night jobs: reconciliation, file transforms, EDI, invoice generation | Wrap or rewrite — it is your business logic, not a UI problem |
| Spreadsheet with teeth | Excel + VBA doing month-end, costing, or planning | Wrap (script it) or replace with a purpose-built tool |
| Device glue | Talks to a scale, a PLC, a card reader, a 1990s scanner | Keep it. Wrap it. Do not replace what the hardware expects. |
The most common mistake I see is applying a "replace" strategy to a "batch computer." You will spend six months buying software that does 80% of what the night job did, and discover the last 20% is the part your customers actually see.
Step 3 — Extract the logic before you can lose it
This is the step that separates a controlled retirement from a fire drill. You need the rules, not the code. The code is a lossy encoding of a decision someone made in 2004. To recover it:
- Interview the operator, not the developer. The developer may be gone; the operator is still running it every month. Sit with them while they do a real run. Write down every question they ask the system and every exception they handle by hand. That list is the specification.
- Replay one real input cycle. Feed the new system the same inputs the old one received last month, and compare outputs field by field. Differences are either bugs in your new system or business rules you never knew existed. Both are findable only this way.
- Export the data, twice, and verify. Not "backup" — export. Open every table in the destination. Count rows. Sum the money columns. A backup you have never opened is a rumor, not a backup.
- Freeze the old system read-only before you touch it. Not deleted — read-only. The day you discover a report the new system can't reproduce is the day you are grateful this copy still exists. I have kept old systems read-only for a full year and handed them to the next company that bought the business.
A concrete example of a hidden rule I have found during these retirements, more than once: the "discount" field that was not a discount at all, but a customer-tier code that a report downstream decoded differently. The old system and the report were two halves of one algorithm, written by two different people in two different years. The code of either half, alone, is wrong.
Step 4 — Choose: contain, wrap, rewrite, or replace
Now that you know what the system is and what it really does, pick the option that fits. This is the honest comparison I use with clients — same framework as my general legacy-app decision guide, specialized for VB6/VBA:
| Option | Typical cost | Time | Choose it when… |
|---|---|---|---|
| Contain | Low | Days–weeks | It is a device-glue app or a small batch job, stable for a decade, and replacement would cost 10× its value |
| Wrap | Medium | Months | The logic is sound but the delivery is failing: old OS, old machine, no one who can run it |
| Rewrite | High | 6–18 months | The logic itself is your competitive advantage and no product does it |
| Replace | Medium (recurring) | Weeks–months | It is a form-over-a-database and a modern SaaS tool already does 90% of it |
Contain — and yes, sometimes this is the answer
A 20-year-old batch job that reconciles a niche manufacturing process may be cheaper and safer to protect than to replace. Containing properly means: real off-site backups of the database, a machine that actually receives security patches, a written runbook, and a named human owner. If your containment today is hope, that is not containment — that is the risk, wearing containment's clothes.
The practical move here is to get the app onto a current, patched, backed-up host and stop running it on the machine in the corner that will die before you retire. Managed Windows hosting is the honest option for this — for example, a Cloudways-managed instance ↗ for the database and a small Windows VM for the VB6 runtime, with real backups. Affiliate link — I may earn a commission if you sign up; you pay the same price either way.
Wrap — the option most businesses skip
Most legacy systems have two halves: a business brain and a delivery body. The body (a Win32 client, a local server, a scheduled Windows task, a 2003 ODBC driver) is what's failing. The brain is often fine. Putting the brain on a current platform — and sometimes giving it a simple web front end — removes 70% of the risk at 30% of the cost of a rewrite. For a VB6 app, "wrap" usually means: a thin web form that writes to the same database, with the old app left read-only for reporting. The rewrite you almost did is now a two-week job.
Rewrite — choose it only if the logic is the moat
If the specific way your application computes things is a genuine competitive advantage and no product on the market does it — rewrite. But budget for discovery, not just code. Rewrites fail most often because they force you to rediscover requirements that were never written down, and the person who knew them has left. The Step 3 interview and replay are not optional prep; they are the project.
Replace — when your "in-house app" is really a CRM or a ledger
If your VB6 application is a form over a database, and that database is customer contacts, orders, or invoices — a modern SaaS tool will do 90% of the job at a fraction of the lifetime cost of owning it. For CRM-shaped systems, HubSpot ↗ has a genuinely usable free tier and is the standard answer; for lightweight internal tracking, Notion ↗ covers more territory than most teams expect. Affiliate links. The hard part is not the software; it's the last 10% of behavior and the data migration, which is exactly why Steps 1–3 come first.
Step 5 — Migrate at a boundary, and keep the old system alive for 90 days
- Run both in parallel for one full cycle. One full month-end, or one full order cycle. Parallel is the only way to catch the edge case that was never in the spec — and in a VB6 system, the spec was in one person's head.
- Cut over at a natural boundary. Month-end, season change, contract renewal — any moment where a clean state is natural. Mid-cycle cutovers are how you end up with two sets of invoices for the same month.
- Keep the old system read-only for 90 days. Not deleted. Read-only. This single step has saved more businesses than I can count, including one where the "replaced" report turned out to be the one the bank actually read.
- Write the runbook for the new system on day one. The first person to need it will be working a shift, not planning one.
The red flags that mean "act this quarter"
- The only person who can fix it is leaving — or has left, and you have noticed it has been "fine" lately, which is exactly how these end
- The server is running an OS that no longer receives security updates
- Your backup is "we copy the .mdb / .accdb to a USB drive sometimes"
- You cannot name who to call when it breaks
- A new hire asks "what does this even do" and there is no answer in writing
- Any two of the above: act. All of them: start this month, not this year.
Where to go next
- Not sure which of the four options fits your system? → Retiring a Legacy In-House Application: A 2026 Decision Guide
- Your system is Access-shaped? → Microsoft Access Alternatives: A 2026 Comparison