Adobe Commerce documentation specifies that Inventory Management decouples physical on-hand quantities at physical sources from virtual salable quantities across customer-facing stocks [1] [2]. Placing an order does not deduct physical stock; instead, it appends a negative hold to the inventory_reservation table [1]. Salable quantity is calculated dynamically as aggregated source quantity minus out-of-stock thresholds plus the sum of active reservations [1] [2]. When conducting physical stocktaking while orders are flowing, updating source items without accounting for pending reservations causes double-deductions or phantom stockouts [4] [5]. Merchants must audit reservation health using bin/magento inventory:reservation:list-inconsistencies and issue compensating reservations before synchronizing floor counts [4].
1. The Dual-Layer Architecture: Physical Sources vs Virtual Stocks
In legacy Magento versions prior to 2.3, inventory management tracked a single global quantity value for each catalog product [6]. In multi-warehouse or omnichannel retail, this structure created database row locks during checkout and forced merchants to rely on custom extensions to represent separate fulfillment facilities [2] [6]. Adobe Commerce introduced Multi-Source Inventory (MSI) to decouple physical warehousing locations from customer-facing storefronts [2] [6].
Under this architecture, physical locations are modeled as Sources [2]. A source represents an individual warehouse, retail store, distribution center, or third-party drop shipper where product units are stored and packed for fulfillment [2]. Each source maintains its own on-hand inventory balances and stock status flags within the inventory_source_item database table [2] [5].
Storefront channels do not read directly from individual sources [2]. Instead, Adobe Commerce models customer availability through Stocks [2]. A stock is an aggregated virtual inventory pool assigned to one or more sales channels (such as websites or store views) [2]. A sales channel can associate with only one stock, but a single stock can aggregate inventory across multiple physical sources [2]. When a customer browses a website, the platform evaluates the aggregated availability across all sources assigned to that website's designated stock [2].
| Entity | Database Representation | Operational Scope | Functional Purpose |
|---|---|---|---|
| Source | inventory_source and inventory_source_item | Physical facility (warehouse, store, 3PL) | Tracks physical on-hand inventory quantities and operational address metadata [2] [5] |
| Stock | inventory_stock and inventory_stock_source_link | Virtual inventory pool per sales channel | Aggregates multiple physical sources and links them to one or more websites [2] |
| Sales Channel | Store website or B2B customer group | Customer storefront interface | Determines which stock provides salable inventory for a browsing customer [2] |
| Reservation | inventory_reservation | Transaction ledger per stock and SKU | Places temporary holds on stock availability without locking physical source rows [1] |
2. The Mathematical Definition of Salable Quantity
Rather than decrementing physical source inventory during checkout, Adobe Commerce calculates a dynamic metric termed Salable Quantity [1] [2]. Salable quantity represents the real-time availability of a SKU across all physical sources assigned to a stock, adjusted for safety thresholds and active customer orders [1] [2].
According to Adobe Commerce documentation, the platform evaluates salable quantity using the following formula [1] [2]:
Salable Quantity = Aggregated Physical Quantity - Out-of-Stock Threshold + SUM(Reservations) [1] [2].
The components of this calculation operate as follows:
- Aggregated Physical Quantity (StockItem Quantity): The sum of on-hand units across all active physical sources assigned to the target stock [1] [2]. For example, if a merchant assigns three sources to Stock A with Baltimore holding 20 units, Austin holding 25 units, and Reno holding 10 units, the aggregated base count is 55 units (20 + 25 + 10 = 55) [1].
- Out-of-Stock Threshold: A configurable buffer value subtracted from the aggregated count to guard against stockouts or manage backorders [1] [2]. If backorders are disabled, a positive threshold reserves safety stock; if backorders are enabled, a negative threshold permits ordering below zero up to the configured limit [1] [2].
- SUM(Reservations): The mathematical sum of all quantity rows in the
inventory_reservationtable matching the product SKU and stock identifier [1]. Initial reservations placed during checkout are recorded as negative numbers [1].
To illustrate how reservations alter customer availability, consider the documented example with 55 base units across Baltimore, Austin, and Reno [1]. If Customer A places an order holding a reservation for 10 units, and Customer B places an order holding a reservation for 5 units, the outstanding uncompensated reservations total -15 units (-10 + -5 = -15) [1]. The platform calculates available capacity as 40 units (55 + -15 = 40) [1]. A third customer attempting to purchase 41 units is blocked, preventing overselling even though physical warehouse shelves still hold 55 unpacked units [1].
3. The Append-Only Reservation Ledger and Lifecycle Events
The core design principle of Adobe Commerce reservations is an append-only transaction ledger [1]. The platform never modifies or updates an existing reservation row [1]. Instead, every order event appends a new row to the inventory_reservation table [1].
| Attribute | Data Type | Documented Function |
|---|---|---|
reservation_id | Integer | System-generated auto-incrementing primary key identifying the ledger record [1] |
stock_id | Integer | Identifier of the stock scope against which the reservation hold applies [1] |
sku | String | Product SKU code associated with the reserved item [1] |
quantity | Float | Quantity delta; negative on initial order placement, positive on fulfillment or cancellation [1] |
metadata | String (JSON) | Contextual JSON string containing event_type, object_type (must be order), and object_id [1] |
The metadata field records specific event types that drive the lifecycle of an order [1]:
order_placed: Triggered upon customer order submission, inserting a negative quantity delta [1].order_canceled: Triggered when an order is partially or fully canceled prior to shipment, inserting a positive compensating delta [1].order_place_failed: Triggered when an asynchronous checkout or payment authorization fails, releasing the initial hold [1].shipment_created: Triggered when the merchant generates a physical shipment, reducing physical source inventory and inserting a positive compensating delta [1].creditmemo_created: Triggered when an item is refunded and returned to stock, restoring source quantity and balancing reservation holds [1] [3].invoice_created: Triggered for virtual and downloadable products that bypass physical shipping [1].
Adobe Commerce documents a three-step lifecycle example illustrating how positive and negative entries balance to zero [1]:
1. A customer orders 25 units of SKU-1. The platform appends row 1 with quantity -25 and event order_placed [1].
2. The customer amends the order, canceling 5 units. The platform appends row 2 with quantity +5 and event order_canceled [1].
3. The warehouse ships the remaining 20 units. The platform decrements 20 units from physical source stock and appends row 3 with quantity +20 and event shipment_created [1].
Across this complete cycle, the sum of quantities is exactly zero (-25 + 5 + 20 = 0) [1].
| Order Status | Lifecycle State | Reservation Hold Behavior | Physical Source Effect |
|---|---|---|---|
| Open | Order placed, awaiting processing | Negative reservation hold active in inventory_reservation | No change to physical source inventory [1] [3] |
| Pending / Processing | Payment authorized or processing | Negative reservation hold remains active | No change to physical source inventory [3] |
| On Hold / Suspected Fraud | Manual review or fraud verification | Negative reservation hold remains in place until approved or canceled | No change to physical source inventory [3] |
| Canceled | Canceled before payment or fulfillment | Positive compensation reservation appends, returning hold to salable quantity | No physical stock deducted [1] [3] |
| Complete | Invoiced and shipped in full | Positive compensation reservation appends; physical inventory deducted at assigned source | Source quantity reduced by shipped count [1] [3] |
| Closed | Refunded via credit memo with return to stock | Compensating reservation clears hold; physical stock added back to source | Source quantity restored for returned items [3] |
Because every completed order leaves balanced reservation rows in the database, the table grows continuously over time [1]. Adobe Commerce includes a scheduled cron job, inventory_cleanup_reservations, which runs daily at midnight by default [1]. This job queries the database for completed reservation sequences whose net sum is zero and deletes the balanced rows in bulk, preventing table bloat while preserving active holds [1].
4. Why Physical Stocktaking Desynchronizes Salable Quantity
Physical stocktaking—whether conducted as an annual wall-to-wall count or continuous cycle counting—measures physical units resting in warehouse bins and pallet racking. When warehouse teams finalize a count, they write updated numbers into the platform. In Adobe Commerce, this update targets the physical source layer (inventory_source_item) via the Admin panel, a CSV import, or the REST API endpoint POST V1/inventory/source-items [5].
However, because Adobe Commerce separates physical source items from virtual stock reservations, updating physical quantities while customer orders are in progress introduces severe synchronization risks [4] [5].
Consider what happens when a warehouse conducts a count on an active SKU while orders are pending fulfillment:
- Scenario A: Counting unpicked shelf stock. If the stocktaking team counts units on the shelf before the warehouse wave has picked pending orders, the shelf count includes units that already have negative reservation holds in
inventory_reservation[1]. Overwriting the source item quantity with this shelf count is safe, because active reservations will correctly prevent those units from being sold again online [1]. - Scenario B: Counting after pick execution. If pickers have already removed 10 units from the bin to a packing cart, but the shipping clerk has not yet created the shipment in Adobe Commerce, physical shelf stock is reduced, but the system's
inventory_source_itemhas not been decremented [1] [3]. If the stocktaking counter records only remaining shelf units and overwritesinventory_source_item, the platform will deduct those 10 units twice: first when the counter overrides the base quantity downwards, and second when the shipping clerk finally records the shipment and triggers the physical source deduction [1] [3].
In addition to timing overlaps, Adobe Commerce documentation identifies administrative events that create permanent reservation leaks (orphaned reservations that never resolve to zero) [4]:
- Upgrading to version 2.3 or later while orders remain in an incomplete state (such as Pending or Processing) [4].
- Changing the global configuration setting Manage Stock from No to Yes while orders are in progress [4].
- Reassigning a Stock to a different Website while active orders are processing through checkout [4].
- Unassigning a physical source from a product that still has pending reservations tied to open orders [1] [5].
When an orphaned reservation persists, the platform continuously subtracts ghost quantities from storefront availability [4]. Merchandisers see items displayed as out of stock online even when physical warehouse shelves hold abundant inventory [1] [4].
5. Detecting and Resolving Inconsistencies with the Inventory CLI
Because reservation holds exist only as database rows in inventory_reservation, merchants cannot inspect or edit them through the standard Adobe Commerce Admin user interface [1] [4]. Adobe Commerce provides two dedicated command-line utilities to audit and correct reservation discrepancies [4]:
bin/magento inventory:reservation:list-inconsistencies [4]
bin/magento inventory:reservation:create-compensations [4]
The inventory:reservation:list-inconsistencies command scans order records and reservation rows to identify orders whose reservations do not balance with their actual fulfillment state [4]. The command supports four operational flags [4]:
-c,--complete-orders: Scans orders in completed states to identify lingering reservation holds that failed to clear upon shipment [4].-i,--incomplete-orders: Scans open, pending, or partially shipped orders to identify missing initial reservations or overcompensations [4].-b,--bunch-size [BUNCH-SIZE]: Defines how many orders to load and evaluate per memory batch during analysis [4].-r,--raw: Formats discrepancies into machine-readable strings structured as<ORDER_INCREMENT_ID>:<SKU>:<QUANTITY>:<STOCK-ID>[4].
When run in human-readable mode, the command outputs the specific discrepancy [4]:
bin/magento inventory:reservation:list-inconsistencies Inconsistencies found on following entries: Order 172: - Product bike-123 should be compensated by +2.000000 for stock 1
In the documented example above, Order 172 completed fulfillment, but its initial reservation hold failed to clear, leaving 2 units held in limbo for stock 1 [4]. To correct this discrepancy, the merchant uses inventory:reservation:create-compensations, passing the exact parameters [4]:
bin/magento inventory:reservation:create-compensations 172:bike-123:+2.000000:1 Following reservations were created: - Product bike-123 was compensated by +2.000000 for stock 1
For automated maintenance pipelines, Adobe Commerce documentation recommends piping the raw output of the detection command directly into the compensation command [4]:
bin/magento inventory:reservation:list-inconsistencies -r | bin/magento inventory:reservation:create-compensations
6. A Stocktaking Reconciliation Protocol for Operations Teams
To conduct physical inventory stocktaking without causing salable quantity drift or overselling, operations and engineering teams must coordinate warehouse floor counts with the platform reservation ledger. The following six-step protocol aligns with SANOCEA recommended operational practice based on Adobe Commerce platform architecture.
Prior to initiating a physical cycle count, run bin/magento inventory:reservation:list-inconsistencies -r to identify any lingering reservation leaks or uncompensated orders [4]. If inconsistencies exist, resolve them using create-compensations so that baseline salable calculations accurately reflect open order commitments [4].
Establish strict staging discipline on the warehouse floor. Differentiate between unpicked inventory residing in storage bins, items picked into fulfillment carts for active pick waves, and packed cartons waiting in dispatch lanes. Never record items from packing carts as available shelf stock [1] [3].
Choose between a localized bin freeze or an offset calculation. If cycle counting during live order flow, note the exact timestamp of the bin count and cross-reference with pick waves released prior to that timestamp. Determine whether unallocated safety stock requires a temporary out-of-stock threshold buffer to prevent new checkouts during counting [1] [2].
Push verified physical on-hand counts directly to the designated facility source using POST V1/inventory/source-items [5]. Specify sku, source_code, quantity, and status (1 for in stock) [5]. Do not modify or clear the inventory_reservation table during stock adjustments; the platform will manage reservation offsets automatically as open orders progress [1] [5].
Immediately following source item updates, verify that storefront salable quantity reflects the formula: Salable Quantity = Physical Source Sum - Threshold + SUM(Reservations) [1] [2]. Re-run bin/magento inventory:reservation:list-inconsistencies to ensure no new discrepancies emerged during the sync window [4].
Log every discrepancy between physical bin counts and pre-count system records. Separate physical inventory shrinkage (theft, bin misplacement, damaged units) from systemic reservation drift (failed checkout rollbacks, abandoned order holds, unassigned source leaks) to continuously refine warehouse pick accuracy and platform health [1] [4].
7. Operational Checks Before Modifying Inventory Sources
Before modifying inventory sources or reconfiguring Multi-Source Inventory settings, engineering and operations teams must verify the following platform conditions:
- Verify that the
inventory.reservations.updateSalabilityStatusmessage queue consumer is active by runningbin/magento queue:consumers:list[1]. If inactive, start the consumer usingbin/magento queue:consumers:start inventory.reservations.updateSalabilityStatus[1]. - Never unassign a physical source from a product while pending orders hold active reservations against that source and stock [1] [5]. Doing so leaves reservations orphaned in the ledger without an assigned source to balance them, permanently corrupting salable quantity calculations [1] [5].
- Confirm that the
inventory_cleanup_reservationscron job runs daily at midnight to purge fully compensated reservation groups whose net quantity equals zero [1]. - Audit all third-party ERP, WMS, and marketplace synchronization connectors. Ensure external inventory integrations write physical stock updates strictly to
POST V1/inventory/source-itemsrather than directly altering core catalog tables or clearinginventory_reservationrows [1] [5]. - Remember that physical stock adjustments update the base on-hand layer only. Reservations remain intact until order fulfillment produces a shipment or cancellation produces a credit memo [1] [3].
Sources
- Adobe Commerce Documentation: Source algorithms and reservations (retrieved 2026-10-14)
- Adobe Commerce Documentation: Stocks and sources (retrieved 2026-10-14)
- Adobe Commerce Documentation: Order status and reservations (retrieved 2026-10-14)
- Adobe Commerce Documentation: Inventory Management CLI reference (retrieved 2026-10-14)
- Adobe Commerce Developer Documentation: Manage source items REST API (retrieved 2026-10-14)
- Adobe Commerce Documentation: Introduction to Inventory Management (retrieved 2026-10-14)
