26 Sept 2026 · 6 min read
Migrating legacy inventory to MSI safely
Move a legacy single-stock store to MSI with a rehearsed cutover that preserves qty, orders and history
Part 7 of the MSI / Inventory series — the cutover, rehearsed before it counts. This is the final post.
Every legacy Magento store holds its inventory truth in one place: cataloginventory_stock_item qty per product, one number per SKU, plus the order history that explains it. MSI replaces that single number with a topology: sources holding qty, stocks aggregating sources, sales channels mapped to stocks, reservations tracking unshipped demand. The migration is not a data copy; it is a reinterpretation of what "in stock" means, performed on a live store where orders keep arriving. Rehearse it on staging until it is boring, or perform it improvisationally on production and remember it forever.
Map legacy qty before touching anything
Start by deciding where each legacy qty number lands. The safe default is one source per website: create a source like legacy-us-web, assign all of that website's legacy qty to it, and link it as the sole source of a stock mapped to the website's sales channel. Storefront behavior then matches the legacy single-number semantics exactly, and you have a working baseline before introducing real warehouses, pickup locations, or priority ordering.
Inventory the edge cases before the first test run. Disabled products still carry qty that must migrate or be explicitly excluded. Configurable children carry the real qty while parents carry none; bundle selections carry qty while bundle parents do not. Grouped product associations follow the same pattern. Dropship or externally fulfilled SKUs with zero local qty need a source representing the external location, or they will read as out of stock the moment MSI takes over. Document each decision in a mapping sheet: legacy SKU range to target source, with reasons. The sheet becomes the reconciliation checklist after each rehearsal.
Run the migration tooling on a staging clone seeded from a recent production snapshot, then reconcile with queries: total legacy qty per SKU versus total MSI source qty per SKU, plus open order counts. Any delta is either an explained exclusion (disabled SKUs, external fulfillment) or a defect. There is no third category.
Freeze, drain, and cut over in a delta window
The final migration always has a delta problem: orders placed after the staging rehearsal do not exist in the rehearsal. Handle it with a defined cutover window. Announce a freeze on order placement, or at minimum on shipment creation, for the window. Take a final production snapshot. Replay the delta: orders placed since the snapshot become reservations in MSI terms, shipments since the snapshot decrement source qty. Keep the window short by rehearsing it; a cutover that takes four hours on staging will take longer on production under stress.
The cleanest sequence for most stores: enable maintenance or a checkout hold banner, snapshot the database, run the qty mapping, replay the order delta, rebuild inventory indexers, probe a sample of simple, configurable, and bundle SKUs on the storefront across each website, then lift the hold. Each step has a verification gate, and the cutover lead has explicit authority to roll back if any gate fails. "Almost correct" inventory is worse than a delayed launch; customers forgive a maintenance page, they do not forgive paid orders for phantom stock.
Reconcile open reservations before go-live
Legacy open orders, unshipped items, pending shipments, are MSI reservations waiting to be acknowledged. For every unshipped order item at cutover, confirm a matching reservation exists so salable qty reflects real demand. The failure mode is oversell: legacy qty migrated gross, reservations missing, storefront shows salable what is already promised to earlier customers.
Reconcile with a three-way check: unshipped order items in sales_order_item, rows in inventory_reservation, and MSI salable qty per SKU per stock. The three must agree within explained tolerance (canceled items pending cleanup, shipments created externally). Pay special attention to partial shipments and bundled items, where one order line maps to multiple reservation rows. Do not go live with an unexplained gap; it becomes oversold orders within hours on any store with velocity.
After go-live, keep the reservation cleanup path running and monitored from day one. Migration rehearsals commonly surface the same orphaned-reservation patterns that later bloat production, which is useful intelligence if it is carried forward into monitoring rather than discarded with the staging database.
The rollback snapshot is the cutover
Before the final run, snapshot everything needed to reverse: a full database backup with a verified restore path, the legacy inventory tables exported separately for fast diffing, the exact migration command sequence with versions, and the pre-cutover indexer state. Time the restore on staging. A backup that has never been restored is a hope, not a plan.
Define the rollback trigger in advance: which verification failures abort the cutover, who calls it, and how far back the rollback goes (revert to snapshot versus fix-forward). Fix-forward is tempting at 2 AM and almost always wrong for inventory: a half-migrated topology with live orders arriving cannot be reasoned about safely. If the gates fail, roll back, diagnose on staging with the captured snapshot, and reschedule. The store loses a maintenance window; it keeps its inventory truth.
Post-cutover, retain the legacy tables read-only for one reconciliation cycle rather than dropping them. They are the audit trail when finance asks why historical stock movement reports shifted, and the fastest way to answer "what did this SKU show last Tuesday" during the first week of MSI operation.
Pitfalls
- Migrating with open carts treated as reserved stock. Carts are not reservations; only placed orders reserve. Subtracting cart qty during mapping understates salability and hides products that should sell.
- Forgetting disabled sources that still hold qty. A disabled source contributes nothing to salability but still appears in qty totals. Reconcile salable qty, not raw qty, and exclude or empty disabled sources deliberately.
- Skipping the rollback snapshot before cutover. Without a timed, tested restore, every verification failure becomes a negotiation about whether to proceed anyway. Snapshot first; decide triggers in advance.
- Migrating bundle and configurable parents as qty carriers. Parents hold no stock; migrating parent qty numbers into a source double-counts. Migrate children and selections; leave parents derived.
- Declaring victory at indexer-green. Rebuilt indexers over a wrong source-to-stock map still sell from the wrong pool. Probe storefront salability per website, place test orders, ship them, and confirm reservations drain before lifting the hold.
Closing the series
This MSI arc moved from concepts (sources, stocks, reservations) through salability checks, source selection, composite products, indexer performance, and finally migration: the full path from a legacy single number to a topology that models how the business actually fulfills. The throughline is that inventory is a promise about the future, not a count of the present. Sources say where, stocks say for whom, reservations say what is already promised, and the cutover is where the promise changes hands without dropping any.
This was the final post in the MSI / Inventory series.