The Ultimate Guide to Magento 2's Multi-Source Inventory (MSI) for Modern Retail

Want to understand Magento 2's MSI without the usual corporate-speak? Good — pull up a chair. This guide walks you through Multi-Source Inventory (MSI) for modern retail: what it is, how it works under the hood (sources, stocks, reservations, selection algorithms), real-world use cases (multi-warehouse, dropshipping, marketplace), integration tips with stock-status extensions, performance tuning for large catalogs, and safe migration steps from the legacy Magento stock system. I’ll also give you hands-on code snippets and CLI tips so you can try things out on a dev instance. No hype. Just the good stuff.
What MSI brings to modern retail
Magento 2’s Multi-Source Inventory (MSI) fundamentally changes how inventory is modeled. Instead of a single global quantity, MSI lets you define multiple physical or logical sources (warehouses, supplier hubs, dropship partners) and assign inventory to each source. The platform then maps sources to sales channels (stocks) and resolves availability at order time using reservations and source-selection logic.
Why this matters:
- Scale: manage multiple warehouses without hacks.
- Flexibility: support dropshipping and marketplace sellers as sources.
- Accuracy: reservations avoid overselling in high-concurrency flows.
- Extensibility: swap or extend source-selection logic for custom business rules.
Core MSI concepts explained simply
Sources
Think of a source as any place stock physically or logically lives. Examples: Main Warehouse, EU Fulfillment Center, Dropship Partner A, Amazon FBA. A source has address, contact, code and a stock level per SKU.
Stocks
A stock binds one or more sales channels (websites) to a set of sources. When a customer on website A places an order, Magento checks the stock associated with website A and uses the linked sources for fulfillment decisions.
Source Items
Source items hold the per-SKU quantity for a source: sku, source_code, quantity, status (enabled/disabled).
Reservations
Reservations are the clever part: instead of immediately decrementing source_item.quantity on order placement (which creates race conditions under concurrent sales), Magento creates a reservation record that adjusts the salable quantity. The inventory tables plus reservations compute the salable quantity for a SKU across sources. Later, when you ship or the order is canceled, reservations are updated/removed. This approach keeps writes lightweight and avoids complex locking.
Source selection algorithms
When an order arrives, MSI needs to decide which source(s) will fulfill it. Magento provides default selection algorithms (priorities and quantity-based decisions) and extension points to implement custom logic (distance, cost, SLA, marketplace rules). You can choose single-source fulfillment or split across sources as needed.
How MSI flows on an order (high level)
- Customer places an order on website.
- Magento resolves the stock for that website.
- Source Selection runs and returns best source(s).
- Magento creates a reservation for the ordered qty (reduces salable qty). Shipment creation will later create shipment source deductions (physically decrement source stock).
- When shipment(s) are created, reservations are consumed and source_item.quantity is adjusted accordingly.
Quick look at MSI tables (useful for debugging)
Inspecting the database is one of the fastest ways to understand state. Common tables you’ll see:
- inventory_source — configured sources
- inventory_source_item — per-source per-sku quantity
- inventory_stock — mapping of stock records to websites and sales channels
- inventory_reservation — reservation records
Hands-on: create a source and assign stock (step-by-step)
Below are realistic examples you can run in a module or a small script on dev. Always test on a non-production environment.
PHP example: create a source programmatically
This code uses service contracts (MSI modules must be enabled). Place it inside a small script or a setup script and run via bin/magento or through an integration endpoint.
use Magento\Framework\App\Bootstrap;
require __DIR__ . '/app/bootstrap.php';
$params = $_SERVER;
$bootstrap = Bootstrap::create(BP, $params);
$objectManager = $bootstrap->getObjectManager();
/** @var \Magento\InventoryApi\Api\SourceRepositoryInterface $sourceRepository */
$sourceRepository = $objectManager->get(\Magento\InventoryApi\Api\SourceRepositoryInterface::class);
/** @var \Magento\InventoryApi\Api\Data\SourceInterfaceFactory $sourceFactory */
$sourceFactory = $objectManager->get(\Magento\InventoryApi\Api\Data\SourceInterfaceFactory::class);
$source = $sourceFactory->create();
$source->setSourceCode('eu_warehouse');
$source->setName('EU Warehouse');
$source->setEnabled(true);
$source->setDescription('Main EU fulfillment center');
$source->setLatitude('48.8566');
$source->setLongitude('2.3522');
$source->setCountryId('FR');
$source->setPostcode('75001');
$source->setCity('Paris');
$source->setPhone('003314000000');
try {
$sourceRepository->save($source);
echo "Source eu_warehouse created\n";
} catch (\Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
PHP example: add stock to a source (source item)
Next, link a SKU to the source with a quantity.
/** @var \Magento\InventoryApi\Api\Data\SourceItemInterfaceFactory $sourceItemFactory */
$sourceItemFactory = $objectManager->get(\Magento\InventoryApi\Api\Data\SourceItemInterfaceFactory::class);
/** @var \Magento\InventoryApi\Api\SourceItemsSaveInterface $sourceItemsSave */
$sourceItemsSave = $objectManager->get(\Magento\InventoryApi\Api\SourceItemsSaveInterface::class);
$sku = 'my-product-sku';
$qty = 25.0;
$sourceItem = $sourceItemFactory->create();
$sourceItem->setSourceCode('eu_warehouse');
$sourceItem->setSku($sku);
$sourceItem->setQuantity($qty);
$sourceItem->setStatus(\Magento\InventoryApi\Api\Data\SourceItemInterface::STATUS_IN_STOCK);
try {
$sourceItemsSave->execute([$sourceItem]);
echo "Source item saved for $sku\n";
} catch (\Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
After running the above, you can reindex and check salable qty:
bin/magento indexer:reindex
php bin/magento cache:flush
-- then check via Admin or the DB table inventory_source_item and inventory_reservation
Working with reservations (example)
Reservations are created automatically when an order is placed. But for testing or fixing states you might create reservations manually on dev. Here’s a simplified example.
/** @var \Magento\InventoryReservationsApi\Api\ReservationInterfaceFactory $reservationFactory */
$reservationFactory = $objectManager->get(\Magento\InventoryReservationsApi\Api\ReservationInterfaceFactory::class);
/** @var \Magento\InventoryReservationsApi\Api\SaveReservationInterface $saveReservation */
$saveReservation = $objectManager->get(\Magento\InventoryReservationsApi\Api\SaveReservationInterface::class);
$reservation = $reservationFactory->create();
$reservation->setSku('my-product-sku');
$reservation->setQuantity(-2); // negative to reduce salable quantity by 2
$reservation->setMetadata([ 'order_id' => 'test-123' ]);
try {
$saveReservation->execute([$reservation]);
echo "Reservation created\n";
} catch (\Exception $e) {
echo "Reservation error: " . $e->getMessage() . "\n";
}
Notes: API names for reservations exist in the Inventory Reservations API package. Some symbols can be different depending on Magento minor version — always check your installed module interfaces.
Integrating MSI with stock-status extensions (e.g., Force Product Stock Status)
Extensions that override product stock status (showing product as in-stock regardless of quantity, or forcing pre-order badges) must work with MSI's salable quantity and reservations, not the legacy qty field. When you integrate a stock-status extension, keep these rules in mind:
- Read salable quantity, not source_item.quantity. Salable quantity = sum(source_item.quantity) + sum(reservations).
- Hook into the proper view or service: use the inventory APIs (MSI salable quantity providers) rather than direct DB reads.
- If extension updates stock visibility, ensure it triggers reindex or invalidates relevant caches and indexers so the storefront shows correct status.
Practical: small plugin to make Force Product Stock Status respect MSI
If an extension checks product stock by reading cataloginventory_stock_item.qty, create a plugin around its method and replace the qty check with salable qty. Example (conceptual):
namespace Vendor\Module\Plugin;
use Magento\InventorySalesApi\Api\GetProductSalableQtyInterface;
class ForceStockPlugin
{
private $salableQtyService;
public function __construct(GetProductSalableQtyInterface $salableQtyService)
{
$this->salableQtyService = $salableQtyService;
}
public function aroundIsProductInStock($subject, $proceed, $sku, $websiteCode)
{
// get salable qty from MSI
$salableQty = $this->salableQtyService->execute($sku, $websiteCode);
if ($salableQty > 0) {
return true; // treat as in stock
}
// fallback to original behavior if needed
return $proceed($sku, $websiteCode);
}
}
Where GetProductSalableQtyInterface is the recommended way to fetch salable quantities per SKU & website (stock). This keeps the extension compatible with MSI and avoids incorrect "in-stock" badges when there are no salable items.
Concrete use cases and implementation notes
1) Multi-warehouse fulfillment
Scenario: you have warehouses in EU and US. You want EU orders to ship from EU whenever possible.
Implementation sketch:
- Create two sources: eu_warehouse and us_warehouse.
- Set shipping priority / source selection rules to prefer eu_warehouse for EU-based websites/stock.
- Assign stock to sources via source_items or import.
- Monitor reservations and adjust fulfillment workflows so pickers see the chosen source per order.
2) Dropshipping
Scenario: you sell products fulfilled by third-party dropship partners.
Approach:
- Create a source per dropship partner and map a contact URL or email in source metadata so your operations team knows where to send purchase orders.
- When orders reserve stock for dropship sources, trigger an integration (webhook / API call) to the partner with line items and quantities. Because reservations happen instantly, the partner will see that the order was reserved for them and can prepare stock.
- When shipment confirmation arrives from partner, create the shipment in Magento and deduct source inventory (consuming reservation or generating a source deduction).
3) Marketplace
Scenario: multiple sellers list on your site and each seller has inventory.
Approach:
- Each seller corresponds to one or more sources (seller_123_source).
- Source metadata contains seller id and commission rules.
- Use custom source selection to select seller source(s) based on price, SLA, or seller reputation.
Optimizing MSI for large catalogs and high volume
MSI works fine for small catalogs out of the box, but large catalogs and high order volume require attention. Here are practical strategies.
Indexing strategy
Magento indexing affects inventory readonly views. Ensure inventory-related indexers are set to 'Update by Schedule' and that cron is reliable. Long-running reindexes during peak can cause stale salable values, so schedule heavy reindex jobs to quieter windows and use incremental reindex where possible.
Batch operations
When importing or updating thousands of SKUs, use bulk source item APIs instead of per-sku updates. Bulk operations reduce overhead and reindex pressure.
Reduce reservation churn
Every order action generates reservations. If your store creates many ephemeral reservations (abandoned carts, test orders), clean up stale reservations and ensure you don’t generate reservations from background test flows. You can also consolidate reservation processing if you have a custom order flow.
Use message queues
Offload heavy inventory operations to asynchronous consumers using Magento’s message queue system (RabbitMQ, Redis streams). For instance, source selection for very large orders can be processed asynchronously and then the frontend can show a validation step to the merchant. This prevents timeouts in synchronous checkout flows.
Database and infrastructure tips
- Employ a dedicated DB replica for heavy read operations (reporting, inventory queries) and keep writes on the master.
- Index the inventory_reservation table and archive old reservations if appropriate for compliance (beware of audit requirements).
- Tune innodb_buffer_pool_size and other MySQL settings for your dataset size.
- Use Redis for caching and session storage to reduce DB load.
Caching and storefront performance
Cache UI-level stock indicators and only invalidate on real changes. For example, use Varnish + Magento's cache layers to avoid hitting inventory services on every product page view. For product list pages where many SKUs are displayed, precompute salable quantities and cache them with a TTL that matches how often inventory changes.
Monitoring & debugging MSI state
Common commands and checks:
- Reindex: bin/magento indexer:reindex
- Check inventory tables: SELECT * FROM inventory_source_item WHERE sku = 'your-sku';
- Check reservations: SELECT * FROM inventory_reservation WHERE sku = 'your-sku' ORDER BY created_at DESC;
- Use Admin > Catalog > Sources to visually check source stock.
Migration best practices from legacy Magento stock
Moving from the legacy single-stock system to MSI is a critical project. Here’s a pragmatic checklist and suggested steps to minimize risk.
1) Audit current stock state
Export inventory from cataloginventory_stock_item and sales history to understand historical sell-through, reserved orders, and backorders. Identify SKUs with negative or odd quantities.
2) Plan source mapping
Decide how your old single stock maps to new sources. Often teams create a single default source to mirror legacy behavior, then gradually introduce additional physical sources and move SKUs in phases.
3) Create sources first
Create your sources and source metadata before migrating quantities. This lets you import quantities directly into inventory_source_item.
4) Migrate quantities and create initial reservations
When migrating, compute an initial salable quantity and populate inventory_source_item. For orders that are already in flight, create reservation records so the migrated salable quantity reflects committed sales.
5) Reindex and verify
After migration, run reindexers and spot-check salable quantities for high-value SKUs. Compare totals: sum of source quantities + reservations should equal the legacy qty if you mapped one-to-one.
6) Test through the full order lifecycle
Place test orders that cover standard, partial shipment, cancellation, and returns flows. Ensure reservations are created and consumed as expected, and that shipments deduct source quantities correctly.
7) Run migration in phases
For large catalogs, do a phased rollout: start with a subset of SKUs or a non-critical website, monitor, then expand. Have rollback plans ready (backup the inventory tables).
8) Communicate with ops and partners
Warehouse teams and dropship partners must know the new identifiers and flows. Provide training and run sample fulfillment operations end-to-end.
Common pitfalls and how to avoid them
- Reading legacy qty: Don’t build features that read only cataloginventory_stock_item.qty — it will misrepresent availability under MSI.
- Not handling reservations: Make sure custom integrations adjust reservations when orders are changed externally (cancelled, refunded, partially shipped).
- Poor source selection rules: If defaults are used without testing, orders might route suboptimally (higher shipping costs, split shipments). Test rules with real-life scenarios.
- Mass updates without reindex strategy: Bulk updates can flood the indexer and create stale data. Use bulk APIs and schedule reindexing.
Developer tips & tricks
- Prefer service contracts (InventoryApi) instead of direct SQL when manipulating inventory from code to stay upgrade-safe.
- Use feature flags or config toggles to enable/disable custom source-selection algorithms during rollout.
- Write integration tests that cover the salable quantity calculations, not just the source_item.qty mutations.
Putting it all together: a small end-to-end example
This end-to-end scenario shows the lifecycle for an order that reserves and then ships from a chosen source.
- Create source (eu_warehouse) — see above script.
- Add 50 units of SKU A to eu_warehouse — see sourceItem example.
- Place an order for 2 units on website linked to the stock that includes eu_warehouse. Magento creates a reservation (-2) for SKU A.
- Warehouse receives the picking request. You create shipment in Magento specifying the eu_warehouse as source. Magento consumes the reservation and decrements inventory_source_item.quantity by 2.
- Orders complete, returns create positive reservations (increasing salable qty until processed), refunds adjust accordingly.
Checklist before going live with MSI
- All sources created and validated.
- Stock assignments for websites are correct.
- Integrations and extensions read salable qty, not legacy qty.
- Reindex and cron are healthy.
- Monitoring for inventory_reservation and source_item anomalies is in place.
- Staff training for fulfillment workflows is completed.
Final thoughts
Magento 2’s MSI brings a lot of power — it enables complex, modern retail flows like multi-warehouse fulfillment, dropshipping, and multi-seller marketplaces. But that power comes with responsibility: design your sources and stocks thoughtfully, integrate extensions against salable quantities, and invest in infrastructure and reindexing strategies for large catalogs. Plan migration carefully and run iterative rollouts. If you keep your architecture modular (source-selection plugins, async flows for heavy operations) you’ll be able to evolve business rules without a major rewrite.
For Magefine customers: consider pairing MSI-enabled stores with hosting tuned for Magento (fast PHP FPM, Redis, proper DB sizing) so inventory queries and indexers run smoothly. If you use extensions that change product visibility or stock display, make sure they explicitly support MSI or adapt them to read salable quantities.
Want me to help with a migration plan or an MSI performance audit for your setup? Tell me about your number of SKUs, order throughput, and fulfillment model and I’ll sketch a focused plan.