Every Odoo implementation reaches the same awkward meeting. Someone asks how much history is coming over from the old system, and the honest answer — less than you were hoping — lands badly. Data migration is where implementations quietly lose weeks, and the cost is rarely the technical loading. It is the negotiation about scope that happens after loading has already started.
A cleaner way to think about it: you are not copying a database. You are opening a new set of books and stocking a new warehouse. Everything you move has to earn its place.
Start from the opening balance, not from the archive
The first question is not "what data do we have" but "what does the business need on day one to operate and to close its first month". That list is shorter than most teams expect:
- An opening trial balance as of the cutover date
- Open customer invoices and open vendor bills, with their aging intact
- Stock on hand by location, with valuation
- Open sales orders, purchase orders, and — in manufacturing — open work orders
- Master data: customers, vendors, products, chart of accounts, taxes, bills of materials
If a record is not needed to run a transaction or to close a period, it is history, and history has other places to live.
Master data moves, but not as it is
Master data is the one category that always moves in full, and the one that most deserves rework on the way. Legacy customer lists carry the same company three times under three spellings. Product masters carry items discontinued years ago. Charts of accounts carry accounts opened for a single journal entry nobody remembers.
Migration is the only cheap opportunity you will ever get to fix this. Once the data is inside Odoo and users have posted against it, deduplication stops being a spreadsheet exercise and becomes a change-management project. Set naming conventions before the first template goes out, name an owner on the client side for each master data set, and make deduplication an explicit deliverable rather than a hope.
Closed history usually stays where it is
This is the recommendation that meets the most resistance, so it is worth stating plainly: loading five years of closed invoices into Odoo rarely pays for itself. The loading is slow, the reconciliation is slower, and the documents arrive stripped of their original approvals, attachments, and context anyway — which means finance goes back to the old system for anything contested.
Retention obligations are real, but a retention obligation is a retrieval obligation. It does not require the records to live inside your new ERP. Three options usually satisfy auditors and users at once:
- Keep the legacy system running read-only for a defined period, with a small named user group
- Export closed history to a reporting database or warehouse, where it can still be queried
- Export document sets to indexed PDF archives when the old system is being decommissioned entirely
Where a client genuinely needs comparative reporting inside Odoo — year-on-year sales by customer, for example — the usual compromise is summarized history: monthly totals by account or by customer, not the underlying documents. It answers the reporting question at a fraction of the effort.
Cleaning happens before the load, and the client does it
Consultants can transform, map, and validate. They cannot decide which of two similar customer records is the real one, or whether a product with no movement in four years is discontinued or seasonal. Those are business decisions, and pretending otherwise is how migrations stall.
What a good partner owes you here is tooling and feedback speed: clear templates, validation that runs in minutes rather than days, and error reports written in business language — "12 customers have no tax treatment set" rather than a stack trace. Our migration work sits inside a broader Odoo implementation approach for exactly this reason: the data workstream needs the same discipline as the process workstream.
Rehearse the migration more than once
A single migration run before go-live is a gamble. Plan for at least three: an early one to surface structural problems while the mapping can still change, a mid-project one to test volumes and runtime, and a full dress rehearsal on production-like infrastructure with the real cutover sequence and the real timings.
Each rehearsal should end with the same reconciliation pack, and each pack should be signed:
- The trial balance in Odoo matches the legacy trial balance to the cent
- AR and AP aging buckets match, customer by customer and vendor by vendor
- Stock valuation matches by location and by product category
- Record counts match for active customers, vendors, and products
When those four match and someone from finance and someone from operations have signed, the argument about data quality is over. When they are skipped, that argument resurfaces two weeks after go-live, in front of an auditor.
The trade-off worth naming out loud
Migrating less is faster and cheaper, and it puts more weight on users in the first months — they will occasionally need the old system. Migrating more feels safer and consumes weeks that would otherwise go into training, testing, and process design.
Across implementations in the UAE, Saudi Arabia, and Egypt, the teams that moved a lean data set and spent the saved time on training went live more calmly than the teams that moved everything. The data was never what made adoption hard. Preparation was.
