Skip to content

BuildNot yet confirmed elsewhere1 publisher2 min readPublished

Shopify reserves checkout stock in MySQL by locking one row per unit

Shopify moved stock reservation from Redis into its MySQL ledger, using one row per available unit, capped at 1,000 per item and location. A dev.to analysis says the limit that remained was how long checkout held database connections, even with fast reservation queries.

The Engineer · Build desk

How we use AISend a correction

Illustration accompanying Shopify reserves checkout stock in MySQL by locking one row per unit
Generated illustration

What happened

  • Under the old Redis design, a paid order updated MySQL and cleaned up Redis in separate writes, so an interrupted sequence could oversell stock or leave it unsellable.
  • Shopify's earlier attempt at MySQL reservations used a single quantity row, so competing checkouts queued on its lock and extra workers only added waiters.
  • Reserve places a temporary hold when a customer starts payment, and claim permanently deducts the stock from the ledger only after payment succeeds.
  • The old counter also lumped all stock together, ignoring whether a unit's location could actually fulfil the order.

Why it matters

  • constraint A sold-out signal has to come from the ledger or application logic, because an empty SKIP LOCKED read only means no eligible row was free at that instant.
  • exposure Shoppers competing for the last units get no documented first-come ordering, so which checkout wins depends on which rows happen to be free when its query runs.
  • decision Teams copying the pattern on statement-based MySQL replication must either change replication format or run statements the manual flags as unsafe.

A dev.to analysis of Shopify's engineering account describes the fix for the hot row as a change in what gets locked. Each available unit gets its own row in an eligible pool, and a reservation takes as many rows as the quantity it needs [9]. Two checkouts for the same item can then lock separate units instead of contending for one counter [9]. Selection stays inside the eligible item and location group. It cannot borrow a row from an ineligible group [8]. The ledger can hold more stock than the pool's cap [2]. We think the bounded pool is good engineering. The set of lockable rows stays small, and the ledger remains the source of truth [6].

SKIP LOCKED is what sends concurrent checkouts to different rows. According to MySQL's locking-read documentation, the option excludes rows whose locks cannot be acquired immediately and returns other rows instead of waiting [10]. The manual describes it as a mechanism for queue-like tables [10]. It also warns that queries which skip locked rows return an inconsistent view of the data [11].

The transaction boundary matters as much as the schema. Reserve and claim each run as short database transactions [13]. The reserve transaction releases its row locks, and the stored reservation state keeps the hold in place while payment is processed [13]. In our view this is the right call for checkout. Holding a unit's lock for the length of a payment would put the next buyer back in a queue. The cost is a hold that outlives its lock. The application has to release abandoned attempts without leaving stock permanently unavailable [14].

The connection limit fits the same picture. SKIP LOCKED governs row-lock acquisition only. Other locks, connection queues and replenishment coordination can still make a request wait [15]. We'd expect a checkout that keeps a pooled connection open during slow work elsewhere to hold up reservations, however fast the reservation query itself runs. The write-up frames the case as an interaction between schema, transaction boundaries and connection occupancy [19].

The write-up does not include throughput or latency figures. Its four-unit diagram is a conceptual illustration and does not show a measured Shopify inventory count [18]. For the gains to carry over to another checkout system, two things have to be true. Contention has to spread across many units of the same item at the same location [9]. And the rest of checkout has to return database connections as promptly as the reservation transactions do [3].

What to watch

  • How Shopify refills an item-location pool from the ledger as rows are claimed, given that replenishment coordination is listed as a place requests can still wait.
  • Production figures from Shopify for lock waits or checkout connection hold time before and after the move.
  • How abandoned holds are expired once the reserve transaction has released its locks.

Clarity's read

What the record supports and how the coverage leans. The claims behind it follow.

Reality

Evidence45
Adoption30
Hype gap0
Incentives
Insufficient
Confidence50
Why these scores

Claim ledger

Ranked by verification strength, evidence, and original report placement.

  1. [1]

    Shopify moved inventory reservation from Redis into the MySQL database that already stored its inventory ledger.

    ReportedSupportedSource: dev.to analysis of Shopify's engineering accountView cited source
  2. [2]

    The replacement uses one row per available unit, with a pool capped at 1,000 rows per item/location combination. The ledger can represent additional stock.

    ReportedSupportedSource: dev.to analysis of Shopify's engineering accountView cited source
  3. [3]

    Connection hold time elsewhere in checkout became a scaling constraint even when the reservation queries were fast.

    ReportedSupportedSource: dev.to analysis of Shopify's engineering accountView cited source

Sources

1 independent publisher whose own reporting we read for this story.

  1. dev.to

    1 article · October 9, 2026

    Inventory reservation in MySQL: Shopify's row-lock design

Share your take

Let Clarity write the post for you.

Signed-in readers get a short post drafted on this story in the register they choose — narrative, analytical, or a direct position — editable to the last word before it goes anywhere. The share buttons at the top of this story work without an account.

Topics and entities

Follow any of these and your For You feed starts watching them — no settings page required.

Topics

Entities

Loading related stories