Skip to content
Rush Commerce
Commerce & Retail Tech4 min read

Shopify swapped Redis for MySQL on inventory reservations

Shopify moved checkout inventory reservations from Redis to MySQL SKIP LOCKED and held $5.1M in sales per minute. The lesson for your commerce stack.

The standard advice for high-throughput inventory reservations is "put it in Redis." Shopify just published how it went the other direction — pulling checkout reservations out of Redis and into MySQL — and carried Black Friday on it. If you run a store and have been told your database can't handle the cart, this is the counterexample worth reading.

What actually happened

Per Shopify Engineering, the problem with Redis was never speed. It was atomicity. Reservations lived in Redis while the authoritative inventory ledger lived in MySQL, so no single ACID transaction could span both. That gap produces exactly two failure modes, and merchants hate both: overselling (item sold, ledger never decremented) and underselling (ledger decremented, unit still flagged as reserved). Redis also had no concept of multi-location inventory, which is table stakes once you have a warehouse and a storefront.

The replacement design is deliberately unglamorous. One row per sellable unit, not one row with a quantity column — ten units means ten rows, and reserving three means locking three rows with MySQL's SKIP LOCKED. The pool is capped at 1,000 rows per item/location pair to stop table bloat, with a background process replenishing from the ledger as it drains.

The tuning notes are where the engineering is. A composite primary key cut lock acquisition from two locks per reservation to one by eliminating secondary index overhead. Switching from MySQL's default REPEATABLE READ to READ COMMITTED killed gap locks that were blocking replenishment inserts. Batching line items with UNION ALL collapsed multiple round trips into one.

Then the plot twist: reservations weren't the bottleneck. Connection instrumentation — tagging transactions with comments like /* conn_tag:checkout_completion */ and measuring hold time at the ProxySQL layer — revealed that other checkout code was starving the connection pool. Fixing that removed 50% of reads and 33% of transactions on the primary. Final state at Black Friday 2025 peak, $5.1 million in sales per minute, up 11% year over year: writer CPU under 50%, reader CPU under 16%.

Why this matters for your commerce stack

Most of the "we need Redis in front of the database" architecture we get handed to review is inherited, not measured. Somebody read that pattern in 2016 and it became a requirement. SKIP LOCKED has been in MySQL since 8.0 and in Postgres since 9.5 — the workload that genuinely required a separate in-memory store a decade ago often doesn't now, and every system you add is one more place your data can disagree with itself.

Three things to steal here, none of which need Shopify's scale. Prefer one system of record over two fast ones. If your reservations and your ledger can't be in the same transaction, you have already chosen which way you'll be wrong — you just haven't found out which yet. Instrument connection hold time, not just query time. Low CPU with high queuing means the problem is in the plumbing, and you cannot see that from a slow query log. Ship behind a shadow mode. Shopify ran both systems in parallel with Redis as source of truth, rolled out pod by pod, and kept a kill switch. That's how you replace something load-bearing without a bad weekend.

Their own summary of the goal is the part we'd underline: the win wasn't making reservations fast. It was making them a safe neighbor — not saturating connections or holding locks that degrade every other query on the checkout path. Fast is easy to demo. Not breaking everything else under load is the actual product.

Key takeaways

  • Shopify moved checkout inventory reservations from Redis to MySQL because two systems can't share one ACID transaction
  • The design is one row per sellable unit with SKIP LOCKED, capped at 1,000 rows per item/location and replenished from the ledger
  • A composite primary key halved locks per reservation; READ COMMITTED removed gap locks blocking replenishment
  • The real bottleneck was other checkout code holding connections — fixing it cut 50% of reads and 33% of transactions on the primary
  • Held Black Friday 2025 peak of $5.1M in sales per minute with writer CPU under 50%
  • Rolled out in shadow mode with Redis as source of truth, pod by pod, with a kill switch

Overselling is an architecture bug, not a bad day. We build commerce systems where the reservation and the ledger live in one transaction, and we prove it under load before it meets your busiest hour. See what we've built or bring us your checkout path.

Sources: Shopify Engineering.

  • #inventory
  • #mysql
  • #commerce-architecture
  • #checkout
  • #database
TR

Tommy Rush — Founder, Rush Commerce

Operator turned builder. 15+ years running operations — now shipping the systems businesses run on. More

Get The Rush Report weekly — one email, zero fluff.