Upgrade from Magento MSI
msi-core removes the special treatment of the Default Stock and stops MSI from writing the
cataloginventory_* tables. Stock id 1 is still created at installation, but it is an ordinary
stock: it is indexed, edited and read exactly like any stock you create yourself.
What changes
Section titled “What changes”| Before | After | |
|---|---|---|
inventory_stock_1 |
MySQL view over cataloginventory_stock_status |
real index table, built by the MSI indexer |
| Composite salability in stock 1 | legacy CatalogInventory indexer | Inventory*ProductIndexer |
| Stock item configuration | cataloginventory_stock_item |
inventory_stock_item_configuration (keyed by sku) |
cataloginventory_stock_item / _stock_status |
written on every stock change | never written again |
cataloginventory_stock indexer |
rebuilds the legacy index | registered but inert |
| Stock id 1 | undeletable, sources not assignable | ordinary stock |
The new configuration table is keyed by sku alone, exactly like the legacy one it replaces.
Giving each stock its own manage_stock, backorders or min_qty would be the natural next step in
MSI, but it changes the data model rather than the storage, so it is deliberately left out: a
configuration read for stock 5 answers the same as one read for stock 1.
The legacy read contracts are unchanged and keep working: StockRegistryInterface,
StockStateInterface, StockItemRepositoryInterface, StockStatusRepositoryInterface and
StockManagementInterface are all served from MSI. Code that goes through them needs no change.
The legacy tables are kept, empty and frozen
Section titled “The legacy tables are kept, empty and frozen”The cataloginventory_* tables are not dropped. Their db_schema.xml belongs to
Magento_CatalogInventory, which 42 core modules of Magento Open Source 2.4.9 require through
Composer and which therefore cannot be uninstalled. Declarative schema would recreate the tables on
the next setup:upgrade anyway.
So after the upgrade the tables still exist and still hold whatever rows they had at the moment of the cut. Those rows are stale from that moment on. Nothing updates them, and products created afterwards get no row at all:
a product created after the upgrade cataloginventory_stock_item 0 rows cataloginventory_stock_status 0 rows inventory_source_item 1 row inventory_stock_item_configuration 1 row inventory_stock_1 quantity 33, is_salable 1Truncating them is safe: with both tables empty, the conformance suite, the functional end to end suite and a concurrent checkout run all pass unchanged, and nothing writes a row back. It is nevertheless left as a deliberate decision rather than done for you, and there is a reason to lean against it. A store that still runs an extension reading them fails differently: visibly on a truncated table, silently on a frozen one. But keeping the rows is what lets the write detector see an extension writing them. Reads argue for truncating, writes argue for keeping; neither is free.
What breaks
Section titled “What breaks”Anything that reads cataloginventory_stock_item or cataloginventory_stock_status with raw
SQL, instead of going through the CatalogInventory service contracts. This is an accepted,
documented break: the whole point of the change is that those tables stop being a source of truth.
Every such reader inside Magento itself has been redirected to MSI, including the ones a literal grep
does not find because they reach the table through $stockItemResource->getMainTable():
- the
qtyand stock status columns and filters of the admin product grid; - the Quantity column of the widget grids (product pickers of reviews, url rewrites, bundle options and downloadable);
- the bundle selection filter that builds dynamic bundle prices;
- the stock columns of the product export;
- the bundle and configurable price indexers;
- the low stock report, already replaced by MSI’s own source-based grid.
If you maintain an extension that queries those tables, port it to StockRegistryInterface
(legacy-shaped reads), GetStockItemDataInterface (index reads, per stock) or
GetStockItemConfigurationInterface (configuration). If you cannot, the data it reads will be stale.
Third-party code that writes the legacy tables
Section titled “Third-party code that writes the legacy tables”Writes are not blocked, they are simply ignored: nothing reads those tables back. An extension that
sets a quantity by writing cataloginventory_stock_item directly will appear to succeed and change
nothing. Point it at SourceItemsSaveInterface, or at StockRegistryInterface::updateStockItemBySku(),
which MSI projects onto the default source item.
Because that failure is silent, the upgrade installs triggers that count those writes. Legacy write detection describes what they catch and how to read them.
Upgrading
Section titled “Upgrading”Expect downtime proportional to your catalog size.
-
Back up the database. There is no automatic downgrade, see below.
-
Put the store in maintenance mode.
-
Run
bin/magento setup:upgrade. It applies:ReplaceLegacyStockStatusViewWithIndexTable: drops theinventory_stock_1view and lets the indexer create the real table;MigrateLegacyStockItemConfiguration: copies the per-product configuration fromcataloginventory_stock_itemintoinventory_stock_item_configuration, for the rows of stock 1 in scope 0, the only ones upstream ever wrote. On a large catalog this is the slow step;DisableLegacyStockIndexer: switchescataloginventory_stockback to realtime mode, which is the only way to drop its mview triggers, because the subscriptions have to be removed while the view still knows about them;DetectLegacyStockWrites: installs the triggers that count writes made against the frozen tables. It needs theTRIGGERprivilege and only warns when it is missing.
-
Run
bin/magento indexer:reindex inventory. It is required: stock 1 has no index rows yet. The schema patch already invalidates the indexer, so a cron-driven reindex would eventually pick it up too; do not rely on that during an upgrade window. -
Run
bin/magento indexer:reindex catalog_product_price catalogsearch_fulltext. Both read salability and were fed by the legacy index before. -
Run
bin/magento cache:flushand leave maintenance mode.
cataloginventory_stock stays in the indexer list on purpose: Magento_Elasticsearch declares
catalogsearch_fulltext as depending on it, and the framework throws when an indexer id cannot be
resolved. Reindexing it is a no-op that completes instantly.
After the upgrade, go through Run in production: the salability consumer must be running.
Downgrading
Section titled “Downgrading”There is no downgrade path. Going back to the upstream line needs the legacy tables repopulated from
MSI (quantities from inventory_source_item for the default source, configuration from
inventory_stock_item_configuration) and the inventory_stock_1 view recreated. Restore the backup
instead.
Upgrading between msi-core versions
Section titled “Upgrading between msi-core versions”Minor and patch releases never break, see Versioning. Update the
package, then run bin/magento setup:upgrade and flush the cache. A release that needs more says so
in the changelog under its own entry.
Moving to 1.1.0 or later:
- Grant the adjustment history permission to the admin roles and integrations that should read it. Roles with access to all resources get it automatically. See Adjustment history.
- Optionally write an opening balance, so items that have not moved since the upgrade have a
baseline row:
bin/magento inventory:adjustment:opening-balance. See Opening balance.
Coming from a 1.0.x release older than 1.0.3, run bin/magento indexer:reindex inventory once: rows
left in the stock index by deleted or renamed products are not removed retroactively.