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. Ce guide walks you through Multi-Source Inventory (MSI) for modern retail: what it is, how it works sous le capot (sources, stocks, reservations, selection algorithms), réel cas d'utilisation (multi-entrepôt, dropshipping, marketplace), integration conseils with stock-status extensions, performance tuning for large catalogs, and safe migration étapes from the legacy Magento stock system. I’ll also give you hands-on code snippets and CLI conseils 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 inventaire is modeled. Instead of a single global quantity, MSI vous permet de define mulconseille physical or logical sources (entrepôts, supplier hubs, dropship partners) and assign inventaire to each source. The platform then maps sources to sales channels (stocks) and resolves availability at commande time using reservations and source-selection logic.

Why this matters:

  • Scale: manage mulconseille entrepôts 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 entreprise 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 client on website A places an commande, 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: au lieu de immediately decrementing source_item.quantity on commande placement (which creates race conditions under concurrent sales), Magento creates a reservation record that adjusts the salable quantity. The inventaire tables plus reservations compute the salable quantity for a SKU across sources. Later, when you ship or the commande is canceled, reservations are updated/removed. Cette approche keeps writes lightweight and avoids complex locking.

Source selection algorithms

When an commande 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). Vous pouvez choose single-source fulfillment or split across sources as needed.

How MSI flows on an commande (high level)

  1. Customer places an commande on website.
  2. Magento resolves the stock for that website.
  3. Source Selection runs and returns best source(s).
  4. Magento creates a reservation for the commandeed qty (reduces salable qty). Shipment creation will later create expédition source deductions (physically decrement source stock).
  5. When expédition(s) are created, reservations are consumed and source_item.quantity is adjusted accordingly.

Quick look at MSI tables (useful for débogage)

Inspecting the database is one of the fastest ways to understand state. Common tables you’ll see:

  • inventaire_source — configured sources
  • inventaire_source_item — per-source per-sku quantity
  • inventaire_stock — mapping of stock records to websites and sales channels
  • inventaire_reservation — reservation records

Hands-on: create a source and assign stock (étape-by-étape)

Below are realistic exemples you can run in a module or a small script on dev. Always test on a non-production environment.

PHP exemple: create a source programmatically

This code uses contrat de services (MSI modules doit être enabled). Place it inside a small script or a script de setup 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 exemple: add stock to a source (source item)

Ensuite, 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";
}

Après running ci-dessus, you can réindexer 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 (exemple)

Reservations are created automatically when an commande is placed. But for test or correctifing states you might create reservations manually on dev. Here’s a simplified exemple.

/** @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 peut être different depending on Magento minor version — always check your installed module interfaces.

Integnote 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-commande badges) must work with MSI's salable quantity and reservations, not the legacy qty champ. Quand vous 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 inventaire APIs (MSI salable quantity providers) rather than direct DB reads.
  • If extension updates stock visibility, ensure it triggers réindexer or invalidates relevant caches and indexeurs so the vitrine shows correct status.

Practical: small plugin to make Force Product Stock Status respect MSI

If an extension checks product stock by reading cataloginventaire_stock_item.qty, create a plugin around its méthode 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 cas d'utilisation and implémentation notes

1) Multi-entrepôt fulfillment

Scenario: you have entrepôts in EU and US. You want EU commandes to ship from EU whenever possible.

Implementation sketch:

  • Create two sources: eu_entrepôt and us_entrepôt.
  • Set shipping priority / source selection rules to prefer eu_entrepôt for EU-based websites/stock.
  • Assign stock to sources via source_items or import.
  • Monitor reservations and adjust fulfillment flux de travails so pickers see the chosen source per commande.

2) Dropshipping

Scenario: you sell products fulfilled by tiers dropship partners.

Approach:

  • Create a source per dropship partner and map a contact URL or e-mail in source metadata so your operations team knows où send purchase commandes.
  • When commandes reserve stock for dropship sources, trigger an integration (webhook / API call) to the partner with line items and quantities. Parce que reservations happen instantly, the partner will see that the commande was reserved for them and can prepare stock.
  • When expédition confirmation arrives from partner, create the expédition in Magento and deduct source inventaire (consuming reservation or genenote a source deduction).

3) Marketplace

Scenario: mulconseille sellers list on your site and each seller has inventaire.

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) basé sur prix, SLA, or seller reputation.

Optimizing MSI for large catalogs and high volume

MSI works fine for small catalogs prêt à l'emploi, but large catalogs and high commande volume require attention. Voici practical strategies.

Indexing stratégie

Magento indexation affects inventaire readonly views. Ensure inventaire-related indexeurs are set to 'Update by Schedule' and that cron is reliable. Long-running réindexeres during peak can cause stale salable valeurs, so schedule heavy réindexer jobs to quieter windows and use incremental réindexer where possible.

Batch operations

When importing or updating thousands of SKUs, use bulk source item APIs au lieu de per-sku updates. Bulk operations reduce overhead and réindexer pressure.

Reduce reservation churn

Every commande action generates reservations. If your store creates many ephemeral reservations (abandoned carts, test commandes), clean up stale reservations and ensure you don’t generate reservations from background test flows. Vous pouvez also consolidate reservation processing if you have a custom commande flow.

Use fichier de messagess

Offload heavy inventaire operations to asynchronous consommateurs using Magento’s fichier de messages system (RabbitMQ, Redis streams). Par exemple, source selection for very large commandes peut être processed asynchronously and then the frontend can show a validation étape to the commerçant. This prevents timeouts in synchronous paiement flows.

Database and infrastructure conseils

  • Employ a dedicated DB replica for heavy read operations (rapporting, inventaire queries) and keep writes on the master.
  • Index the inventaire_reservation table and archive old reservations if appropriate for compliance (beware of audit prérequis).
  • 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 vitrine performance

Cache UI-level stock indicators and only invalidate on real changes. Par exemple, use Varnish + Magento's cache layers to avoid hitting inventaire services on every page produit view. For product list pages where many SKUs are displayed, precompute salable quantities and cache them with a TTL that matches how often inventaire changes.

Monitoring & débogage MSI state

Common commands and checks:

  • Reindex: bin/magento indexeur:réindexer
  • Check inventaire tables: SELECT * FROM inventaire_source_item WHERE sku = 'your-sku';
  • Check reservations: SELECT * FROM inventaire_reservation WHERE sku = 'your-sku' ORDER BY created_at DESC;
  • Use Admin > Catalog > Sources to visually check source stock.

Migration bonnes pratiques from legacy Magento stock

Moving from the legacy single-stock system to MSI is a critical project. Here’s a pragmatic checklist and suggested étapes to minimize risk.

1) Audit current stock state

Export inventaire from cataloginventaire_stock_item and sales history to understand historical sell-through, reserved commandes, and backcommandes. 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 mignote quantities. This vous permet de import quantities directly into inventaire_source_item.

4) Migrate quantities and create initial reservations

When mignote, compute an initial salable quantity and populate inventaire_source_item. For commandes that are already in flight, create reservation records so the migrated salable quantity reflects committed sales.

5) Reindex and verify

Après migration, run réindexereurs and spot-check salable quantities for high-valeur SKUs. Compare totals: sum of source quantities + reservations should equal the legacy qty if you mapped one-to-one.

6) Test through the full commande lifecycle

Place test commandes that cover standard, partial expédition, cancellation, and returns flows. Ensure reservations are created and consumed as expected, and that expéditions 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 inventaire 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 comment avoid them

  • Reading legacy qty: Don’t build fonctionnalités that read only cataloginventaire_stock_item.qty — it will misrepresent availability under MSI.
  • Not handling reservations: Assurez-vous custom integrations adjust reservations when commandes are changed externally (cancelled, refunded, partially shipped).
  • Poor source selection rules: If defaults are used without test, commandes might route suboptimally (higher shipping costs, split expéditions). Test rules with real-life scenarios.
  • Mass updates without réindexer stratégie: Bulk updates can flood the indexeur and create stale data. Use bulk APIs and schedule réindexeration.

Developer conseils & tricks

  • Prefer contrat de services (InventoryApi) au lieu de direct SQL when manipulating inventaire from code to stay mise à jour-safe.
  • Use fonctionnalité flags or config toggles to enable/disable custom source-selection algorithms during rollout.
  • Write test d'intégrations that cover the salable quantity calculations, not just the source_item.qty mutations.

Putting it all together: a small end-to-end exemple

This end-to-end scenario shows the lifecycle for an commande that reserves and then ships from a chosen source.

  1. Create source (eu_entrepôt) — see above script.
  2. Add 50 units of SKU A to eu_entrepôt — see sourceItem exemple.
  3. Place an commande for 2 units on website linked to the stock that includes eu_entrepôt. Magento creates a reservation (-2) for SKU A.
  4. Warehouse receives the picking request. You create expédition in Magento specifying the eu_entrepôt as source. Magento consumes the reservation and decrements inventaire_source_item.quantity by 2.
  5. 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 inventaire_reservation and source_item anomalies is in place.
  • Staff training for fulfillment flux de travails is completed.

Final thoughts

Magento 2’s MSI brings a lot of power — it enables complex, modern retail flows like multi-entrepôt 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 réindexeration strategies for large catalogs. Plan migration carefully and run iterative rollouts. Si vous keep your architecture modular (source-selection plugins, async flows for heavy operations) you’ll be able to evolve entreprise rules without a major rewrite.

For Magefine clients: consider pairing MSI-enabled stores with hosting tuned for Magento (fast PHP FPM, Redis, proper DB sizing) so inventaire queries and indexeurs run smoothly. Si vous 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, commande throughput, and fulfillment model and I’ll sketch a focused plan.

Optimize Your MSI Reindexation

Multi-Source Inventory means frequent réindexeration. Keep your store fast with Advanced Index Manager - schedule, monitor, and optimize your Magento indexes.

Discover Advanced Index Manager