MethodBusiness softwareGDPRIntegration
Data migration from a legacy system: a step-by-step method that holds up
10 min read

A reliable migration from a legacy system follows six steps: map what exists, decide what moves, cleanse and deduplicate, write the mapping rules, rehearse with dry runs, then cut over and reconcile. Most failed migrations do not fail on technology. They fail because the work started too late, once the new software was ready and the real state of the old data finally came to light.
This guide is for founders, operations leads and project owners replacing business software, an ERP, a CRM or an in-house tool. It covers the method, the roles, the checks and the traps, whoever does the technical work.
Why data migration is the underestimated workstream
New software projects talk about screens, features and deadlines. Data shows up as one line near the end of the plan: "import data". That is a mistake, for three reasons:
- legacy data carries years of habits: repurposed fields, retired codes, sloppy entries, rules that changed halfway through;
- new software is stricter: a required field, a closed list or an enforced relationship rejects what the old system happily accepted;
- trust is won or lost on day one: if a salesperson finds a duplicate customer or a wrong price on go-live Monday, they go back to their spreadsheet, and the project loses credibility.
Treat migration as a project inside the project, with its own owner, plan and success criteria, started during scoping.
Step 1: map your sources
Before moving anything, draw the map.
- Source systems: the legacy application, but also satellite spreadsheets, Access databases, shared folders and inboxes used as registers. Part of the truth often lives outside the official system.
- Business entities: customers, contacts, products, price lists, orders, invoices, contracts, jobs, stock, attached documents.
- Volumes: record counts per entity and per year.
- Owners: for each entity, the person who can tell whether the data is right.
- Export routes: native export, direct database access, API, flat files. Check early that you can actually get your data out, and how fast. With a vendor, this can be a contract question, covered in our vendor lock-in exit plan.
If the legacy system is an Access database, our guide to converting MS Access to a web app lists the issues specific to that case.
Step 2: decide the scope
Migrating everything is rarely right. Give each entity one of four outcomes:
| Outcome | Which data | Example |
|---|---|---|
| Full migration | Live data used every day | Active customers, open orders, stock |
| Partial migration | History needed in daily work | Orders from the last two or three years |
| Searchable archive | Data you must keep but no longer use | Old invoices, closed files |
| Drop, then delete | No use and no retention obligation | Dead leads, duplicates, test records |
Two constraints frame the decision.
Retention rules. Tax and accounting rules set minimum periods, and they vary by country. In the United States, for example, the IRS's record retention guidance (updated June 30, 2026) sets a default of 3 years for records supporting a tax return, with longer periods in specific cases, and at least 4 years for employment tax records. Other countries require longer: check yours with your accountant. These records do not have to live in the new system, but they must remain accessible.
Personal data. Under the GDPR, which applies to personal data of people in the EU, personal data must be accurate and kept no longer than necessary (Article 5 of the regulation). A migration is the best moment to apply those principles instead of carrying forward data that should already be gone. Our GDPR checklist for business applications covers what the new system itself should handle.
Step 3: profile and cleanse
Once the scope is set, measure quality before fixing anything. A handful of simple queries usually reveals the size of the job:
- the share of empty values in every field the new system makes mandatory;
- values outside the allowed list (free-text countries, invented statuses, mixed units);
- inconsistent formats (dates stored as text, phone numbers in ten styles, amounts with commas or periods as decimal separators);
- broken references (an order pointing to a deleted customer);
- test or training records nobody ever removed.
Then decide where to fix. There are two schools:
- Fix at the source, before migration: users clean the data in the tool they know. Slower, but corrections are validated by the people who understand them.
- Fix in transformation: automated rules normalize formats and fill gaps. Fast and repeatable, provided every rule is written down and approved.
In practice, you combine both: automated rules for format, human correction for meaning.
Step 4: deduplicate
Duplicates are the most visible defect after go-live, and a plain import tool will copy them across without a second thought.
A sound deduplication approach:
- sets matching criteria per entity: company registration or tax number for a business, email for a contact, manufacturer part number for a product;
- separates certain matches from doubtful ones: certain matches merge automatically, doubtful ones go to a human review list;
- picks a surviving record and a merge rule field by field (most recent, most complete, or from a named system);
- keeps a cross-reference of old identifiers, so an invoice or email quoting an old customer number can still be traced.
That last point is often forgotten. Keep the old-to-new ID table: it will be used for years.
Step 5: write the mapping rules
The core document of any migration is the field mapping: for each target field, where the data comes from, what transformation applies, and what happens if it is missing.
| Target field | Source | Rule | If missing |
|---|---|---|---|
| Customer, legal name | Legacy app, NAME field | Trim spaces, fix casing | Reject |
| Customer, country | COUNTRY field (free text) | Convert to ISO country code | Default set by owner |
| Order, status | STATE field (codes 1 to 9) | Conversion table approved by sales ops | Reject |
| Product, price | 2026 price list spreadsheet | Net amount, period as decimal separator | Reject |
Each rule is approved by the business owner of that data, then coded into a repeatable script: you must be able to rerun the whole migration from scratch as many times as needed. A migration done by hand, with copy and paste, can be neither repeated nor audited.
Step 6: rehearse, cut over, reconcile
Dry runs
A dry run is a dress rehearsal: copy the legacy data, run every script, load the result into a test copy of the new system. It serves three purposes:
- timing, to size the cutover window;
- rejects, counted and fixed at the source or in the rules;
- user checks on their own records: their ten biggest customers, their open orders, their best-selling products.
Plan at least two. Stop when results are stable and the owners sign off.
Cutover
There are two strategies:
- big bang: the legacy system is frozen on Friday evening, the migration runs over the weekend, the new system starts on Monday. Easy to explain, but all the risk sits in one window;
- phased: by site, team or module, sometimes with a period where both systems run. Less risky, but data has to be kept in sync during the transition.
Either way, write a rollback plan: at what point, on which criteria, and how you return to the legacy system if reconciliation fails.
Reconciliation
Checks are prepared during dry runs and replayed on the day:
- record counts per entity, source against target, with every reject explained;
- control totals: receivables, stock value, year-to-date revenue, matching to the cent;
- samples checked by hand by business owners;
- real workflows: create an order for a migrated customer, issue an invoice, look up past history.
Roles: who does what
| Role | Responsibility |
|---|---|
| Leadership | Decides scope, accepts or rejects trade-offs |
| Data owners | Approve rules, clean data, sign off dry runs |
| Client project lead | Owns the plan, the reject lists and the decision log |
| Delivery team or vendor | Extracts, transforms, loads, produces reconciliation reports |
The classic mistake is handing everything to the vendor. They know how to move data, not whether a customer inactive since 2019 should come along.
The most expensive mistakes
- Starting when the software is ready. Begin mapping during scoping, in parallel with development.
- Never rehearsing. One migration on go-live day, with no dry run, bets the business on a script that has never run for real.
- Forgetting attachments. Scanned contracts, photos and PDFs are heavy, have fragile file paths and must stay linked to the right record.
- Switching the old system off too soon. Keep it read-only while forgotten cases surface.
- Confusing transfer with validation. "Everything moved" does not mean "everything is right".
When the new system is custom-built
In a custom build, migration has one big advantage: the new data model can be designed from your real data, not the other way round. Mapping rules are written alongside the screens, and dry runs feed the automated tests. Our guide to legacy application modernization builds migration in from day one for that reason.
It is also why we build our free visual prototype, presented over video within 5 working days, on a sample of your real data whenever possible: you see your own customers and orders in the future tool before you decide. Our article on prototypes, MVPs and proofs of concept explains what that first step can tell you.