HN Debrief

We replaced Redis with MySQL for inventory reservations and it scaled

  • Databases
  • Infrastructure
  • E-commerce
  • AI
  • Developer Tools

Shopify’s post describes a checkout problem that only shows up when many buyers race for the same physical inventory at once. Their old design kept the source-of-truth inventory in MySQL but tracked short-lived reservations in Redis, which made oversell protection a cross-system consistency problem. The new design pulls reservations back into MySQL. Instead of decrementing one hot quantity row per SKU, it uses `SELECT ... FOR UPDATE SKIP LOCKED` against a bounded buffer of reservable rows for each item and location. A replenishment process refills that buffer from the main inventory ledger so checkout can avoid hammering one contended counter. The claimed payoff was simpler correctness and lower load on the main database once they also reduced query count and connection pressure.

If you run reservations across multiple datastores, the operational and correctness costs can outweigh the raw speed win. But Shopify’s exact pattern is a scale-specific tradeoff, not a general recipe, so teams should validate their own contention profile before copying the bounded-row design.

Discussion mood

Mixed but engaged. People liked the core idea of collapsing a two-database reservation flow back into one transactional system, but many were skeptical of the bounded-row and replenishment design, and a huge share of comments were irritated by what they saw as obvious AI-written prose that made the post harder to trust and parse.

Key insights

  1. 01

    Flash-sale throughput changes the design

    Hot inventory is not a theoretical edge case when a single SKU can attract hundreds of purchase attempts per second. If a checkout path holds a lock for roughly 500 milliseconds while it does other work, one locked quantity row can cap sales at only a few units per second. That makes the bounded-row approach easier to understand. It is not optimizing average carts, it is trying to stop one celebrity drop or countdown sale from turning a single SKU into a serialized bottleneck.

    Measure the end-to-end time a reservation lock is held, not just the cost of the inventory update itself. If your flash-sale path keeps a hot row locked across payment or service calls, you need a different concurrency model before you need a faster database.

      Attribution:
    • sgarland #1
    • cowsandmilk #1
    • risyachka #1
    • kevincox #1
  2. 02

    The hard part is atomic reservation

    Several proposed alternatives quietly reintroduced the original race. A check that aggregates active carts and then inserts a reservation row looks simpler, but unless the availability check and reservation write happen atomically, two buyers can both see the last unit and both proceed. The point of `SKIP LOCKED` here is not style. It lets concurrent buyers claim disjoint reservable rows without waiting on one shared counter, while the database still enforces the no-oversell invariant.

    Be suspicious of reservation designs that read availability and then write a hold in separate steps. If you cannot explain exactly what prevents two concurrent winners for the last item, you do not have a reservation system yet.

      Attribution:
    • soontimes #1 #2
    • codedokode #1
  3. 03

    Missing SLOs weaken the case

    The post asks readers to accept a fairly intricate design without showing the reservation latency target or the throughput threshold that made simpler options fail. That leaves a hole. Batch reservation, queued checkout, or even tolerating some slower paths might be perfectly reasonable depending on the actual service level objective. Without numbers, the architecture reads more heroic than necessary.

    When you publish or review a scaling redesign, demand the trigger metrics. Tie the new mechanism to a concrete latency, throttling, or oversell threshold so the team knows when the complexity is justified.

      Attribution:
    • soontimes #1
    • solatic #1
  4. 04

    This is a buffer, not per-unit inventory

    A few readers untangled a key misconception in the article. Shopify is not storing every real-world unit as a durable row forever. It keeps at most about 1,000 reservable rows per item-location as a working pool, then refills that pool from the inventory ledger. That distinction matters because it makes the table a concurrency control structure, not the canonical inventory model. It also explains why deleting rows can be fine in MySQL even if some readers expected status updates instead.

    Separate your source-of-truth model from your concurrency-control model. A temporary reservation workspace can look denormalized or weird and still be the right shape if it exists to spread locks, not to represent business truth.

      Attribution:
    • fragmede #1
    • soontimes #1
    • sgarland #1
  5. 05

    Reserving earlier hurts conversion economics

    Moving inventory holds earlier in the funnel sounds cleaner, but it changes the business problem. With high cart abandonment, reserving items at add-to-cart or even early checkout can block real buyers behind shoppers who never convert. Shopify’s choice to reserve near payment time reflects a sales policy as much as a database policy. The system is optimized for 'who actually commits money first gets the item', not for making carts feel like physical baskets in a store.

    Set the reservation point based on revenue behavior before you optimize the database. If abandonment is high, earlier holds may reduce oversells while quietly increasing lost sales.

      Attribution:
    • pas #1
    • zer00eyz #1

Against the grain

  1. 01

    Redis may still be the simpler hammer

    One experienced commenter said a Redis-first stock system handled higher traffic with app-side sharding and much less conceptual machinery. From that angle, Shopify’s design looks like a very expensive way to avoid syncing two systems, especially if your organization already knows how to operate Redis well. The rebuttal was that you still need a transactional database for the purchase record, which means the sync problem never really disappears.

    Do not assume single-store consolidation always wins. If your team already has a durable and well-understood Redis reservation layer, compare total incident and implementation cost against migration complexity instead of treating fewer technologies as automatically simpler.

      Attribution:
    • misiek08 #1
    • theptip #1
  2. 02

    Oversell can be a business choice

    Not every merchant needs airtight no-oversell guarantees. One commenter described a client that occasionally sold the last item twice, then recovered the sale with an apology and discount on an alternative. That is a reminder that perfect inventory correctness is not free, and some businesses would rather spend on customer support than on heavy reservation machinery.

    Match reservation rigor to merchant economics. For some catalogs, a small oversell rate may be cheaper than building and operating high-contention protection for every edge case.

      Attribution:
    • arichard123 #1
  3. 03

    Build specialized storage if scale truly dominates

    A few readers pushed back on the premise that general-purpose MySQL should be the end state at this revenue and scale. They argued that companies with extreme request volume sometimes win by building domain-specific storage engines with narrow query patterns, simpler internals, and aggressive in-memory views. That is far outside normal startup advice, but it does challenge the implied ceiling of off-the-shelf databases.

    If a core workload remains pathological after schema and architecture fixes, custom infrastructure is not absurd. It is only worth considering when the workload is central enough to justify a permanent database engineering function.

      Attribution:
    • znpy #1
    • kgeist #1

In plain english

lock contention
A slowdown that happens when many concurrent operations need exclusive access to the same database row or resource.
MySQL
A widely used relational database management system that stores structured data in tables and supports SQL queries and transactions.
Redis
An in-memory data store often used as a cache, queue, or fast key-value database.
SELECT ... FOR UPDATE SKIP LOCKED
A database query pattern that locks selected rows for a transaction and skips rows already locked by other transactions instead of waiting for them.
SKU
Stock Keeping Unit, an identifier for a specific product or product variant in inventory systems.

Reference links

Database locking and concurrency references

Alternative systems and architecture ideas

Company culture and policy links

Shopify politics and reputation references