Shopify replaced Redis with MySQL for inventory reservations–and it scaled

Shopify replaced Redis with MySQL for inventory reservations–and it scaled

In This Article

    Shopify Replaced Redis with MySQL for Inventory Reservations—and It Scaled

    7 Key Takeaways from One of the Most Surprising Database Migrations in E-Commerce


    Introduction: Why Shopify's Move from Redis to MySQL Matters

    Here's a scenario that keeps e-commerce engineers up at night: Black Friday Cyber Monday (BFCM) is approaching, and your inventory system needs to handle over 1 million requests per second. Every single request is a merchant trying to reserve stock for a customer who's about to check out. One mistake—one oversell, one double-reservation—and you've got angry merchants, canceled orders, and a PR disaster.

    For years, Shopify ran this critical system on Redis. It was fast, in-memory, and purpose-built for high-throughput operations. But as their platform grew to serve millions of merchants worldwide, the Redis-based inventory reservation system became a bottleneck—not because Redis couldn't handle the speed, but because it couldn't handle the consistency.

    So Shopify did something that might seem counterintuitive: they replaced Redis with MySQL. Yes, the same MySQL that powers countless WordPress blogs and legacy CRUD apps.

    And it worked. The new system handles over 1 million requests per second during peak events, achieves sub-10ms latency, and eliminated an entire layer of infrastructure complexity. Here are the seven key takeaways from Shopify's migration that every engineer should understand.


    1. The Redis Bottleneck: Why Shopify Needed a Change

    Redis is an in-memory data store. It's incredibly fast at reading and writing simple key-value pairs. But Shopify wasn't using Redis as a cache—they were using it as a primary data store for inventory reservations. That's a fundamentally different job.

    The Problem with Redis as a Primary Store

    When you use Redis as your source of truth, you inherit a set of problems:

    • Custom sharding: Redis doesn't natively support the kind of horizontal scaling that relational databases do. Shopify had to build custom sharding logic to distribute inventory data across multiple Redis nodes.
    • Replication complexity: To ensure durability, Shopify needed to replicate data across nodes. But Redis replication is asynchronous by default, which means you can lose recent writes in a failover scenario.
    • Data consistency challenges: In a high-concurrency environment where multiple requests are trying to reserve the same item, you need atomic operations. Redis has some atomic primitives, but they don't compose well for complex business logic like partial cancellations or modifications.

    The Tipping Point

    As Shopify's merchant base grew, the operational overhead of managing this custom Redis infrastructure became unsustainable. Every new feature that touched inventory required careful coordination with the sharding and replication logic. And during BFCM, when traffic spiked, the team had to babysit the system constantly.

    Key Takeaway: Redis is excellent as a cache or for simple, ephemeral data. But when you need strong consistency, complex transactions, and durable storage, using it as a primary data store means you'll end up building a lot of infrastructure that a relational database gives you for free.


    2. The MySQL Alternative: Leveraging ACID Transactions

    Why MySQL? Shopify already had deep operational experience with MySQL across their platform. But more importantly, MySQL provides something Redis doesn't: ACID transactions.

    What ACID Means for Inventory

    • Atomicity: A reservation either fully succeeds or fully fails. No partial states where stock is "kind of" reserved.
    • Consistency: The database guarantees that a transaction brings the system from one valid state to another.
    • Isolation: Concurrent transactions don't interfere with each other. If two customers try to reserve the last item, exactly one succeeds.
    • Durability: Once a transaction is committed, it's permanent—even if the server crashes.

    Redis, by contrast, offers eventual consistency at best when used as a primary store with replication. For inventory, that's a dangerous trade-off.

    Row-Level Locking for High Concurrency

    One of the most common misconceptions about MySQL is that it can't handle high concurrency. That's true if you're using MyISAM tables with table-level locks. But with InnoDB (the default engine), MySQL uses row-level locking, which means concurrent transactions on different rows don't block each other.

    Shopify's system was designed to take advantage of this. Instead of locking an entire inventory table, the system locks only the specific SKU row being reserved. This reduces contention by over 90% compared to table-level locking.

    Eliminating the Caching Layer

    Here's the elegant part: because MySQL now handled both storage and consistency, Shopify could eliminate the separate caching layer that previously sat between the application and Redis. The database itself became the single source of truth.

    Key Takeaway: Modern relational databases like MySQL (with InnoDB) are far more capable at handling high concurrency than most engineers assume. The key is designing your schema and queries to take advantage of row-level locking.


    3. The Reservation Token Algorithm: A Custom Solution

    You can't just point MySQL at your inventory problem and call it a day. Shopify had to design a custom algorithm to make reservations work efficiently within the constraints of a relational database.

    What Are Reservation Tokens?

    Think of a reservation token as a unique identifier that represents a specific quantity of stock for a specific SKU, tied to a specific order or cart. Instead of directly decrementing inventory counts, the system creates a reservation record.

    Here's how it works:

    1. A customer adds an item to their cart.
    2. The system creates a reservation token for, say, 2 units of SKU-123.
    3. The token references the SKU row and includes the quantity reserved.
    4. When the order is placed, the token is "consumed" and the inventory count is permanently decremented.
    5. If the cart expires or the customer removes the item, the token is canceled and the stock is released.

    Handling Partial Cancellations and Modifications

    The token approach shines when you need flexibility. A customer who reserved 3 items but only checks out with 2? Split the token. A customer who wants to change the size from M to L? Cancel one token and create another.

    This is where Redis fell short. Doing these operations atomically with custom sharding and replication was a nightmare. In MySQL, it's just a transaction:

    BEGIN;
    -- Cancel old reservation
    UPDATE reservations SET status = 'cancelled' WHERE token_id = 'abc123';
    -- Create new reservation
    INSERT INTO reservations (token_id, sku, quantity, status) VALUES ('def456', 'SKU-123', 2, 'active');
    COMMIT;
    

    Optimistic Locking and Short-Lived Transactions

    To keep latency low, Shopify designed transactions to be as short as possible. They used optimistic locking where appropriate, meaning the system checks for conflicts at commit time rather than holding locks for the entire duration of a request.

    Key Takeaway: The reservation token pattern is a powerful way to model inventory in a relational database. It gives you atomicity, flexibility, and the ability to handle complex business logic without distributed locks.


    4. Performance Under Pressure: Handling 1M+ Requests Per Second

    The skeptical question is always: "Sure, MySQL works for your test environment, but can it handle production traffic?"

    Shopify's answer is a resounding yes—and they proved it during BFCM 2023, which saw $9.3 billion in sales processed through their platform.

    Sub-10ms Latency

    In their engineering case study, Shopify reported that the MySQL-based reservation system achieves sub-10ms latency for reservation requests under peak load. That's comparable to what they were getting with Redis, but with far stronger consistency guarantees.

    Row-Level Locking Reduces Contention

    The shift to row-level locking was critical. In their load tests, Shopify found that contention on inventory rows dropped by over 90% compared to what they'd seen with their previous approach. This meant that even when thousands of requests hit the same SKU simultaneously (think: a viral product drop), the system handled it gracefully.

    Benchmarking Before Migration

    Shopify didn't just flip a switch. They spent months benchmarking and load testing the new system. They simulated BFCM traffic patterns, including the infamous "flash sale" scenario where a single product gets hammered with requests in a matter of seconds.

    Key Takeaway: Performance isn't just about raw speed—it's about predictable performance under load. MySQL, when properly designed, can deliver sub-10ms latency even at massive scale. The difference is that you have to design for it, whereas Redis gives you speed but sacrifices consistency.


    5. Zero-Downtime Migration: A Gradual Rollout Strategy

    Migrating a core system that handles millions of requests per second is terrifying. Any downtime means merchants can't sell, which means lost revenue and damaged trust. Shopify's approach was methodical and cautious.

    Canary Deployment: Starting with 1% of Traffic

    The team began by routing just 1% of live traffic to the new MySQL-based system. This allowed them to validate behavior in production without risking widespread impact. They monitored error rates, latency, and consistency—and when they were confident, they increased the percentage.

    Incremental Traffic Increase and Monitoring

    Over several weeks, Shopify gradually increased the traffic percentage: 1% → 5% → 10% → 25% → 50% → 100%. At each stage, they watched for anomalies. They also built tooling to compare reservation outcomes between the old and new systems, ensuring that no discrepancies slipped through.

    Ensuring Merchant Experience Was Unaffected

    The most important metric was merchant experience. If a merchant's inventory counts were wrong, even for a single SKU, that would be a critical failure. Shopify's monitoring focused on detecting any deviation in inventory levels between the two systems during the migration.

    Key Takeaway: Zero-downtime migrations are achievable, but they require patience and a rigorous rollout strategy. Canary deployments with incremental traffic increases allow you to catch issues early without risking your entire system.


    6. Operational Simplicity: Reducing Moving Parts

    One of the most underrated benefits of this migration is the reduction in operational complexity.

    Eliminating the Redis Cluster for Reservations

    Previously, Shopify operated a dedicated Redis cluster for inventory reservations. That meant managing:

    • Sharding logic
    • Replication configuration
    • Failover procedures
    • Memory monitoring and capacity planning
    • Data persistence and backup strategies

    All of that went away. The reservation system now runs on MySQL, which Shopify already operated at scale across their platform.

    Simplifying Data Consistency and Caching Layers

    The old system had multiple layers: application → cache → Redis → replication. Each layer introduced potential points of failure. The new system is simpler: application → MySQL. The database handles consistency, durability, and concurrency control natively.

    Improved Reliability and Easier Maintenance

    Fewer moving parts means fewer things to break. Shopify reported that the new system is easier to maintain and more reliable in production. When issues do arise, debugging is simpler because there's less infrastructure to investigate.

    Key Takeaway: Sometimes the best performance optimization is removing complexity. Every layer you add to a system is another place where things can go wrong. If a relational database can handle the job natively, you're often better off using it.


    7. Key Lessons for Engineers: When to Choose MySQL Over Redis

    Shopify's migration isn't a blanket statement that "MySQL is better than Redis." It's a lesson in choosing the right tool for the right job.

    Match the Tool to the Use Case

    • Use Redis when: You need a cache, a message queue, or a store for ephemeral data where eventual consistency is acceptable.
    • Use MySQL when: You need strong consistency, durable storage, and the ability to run complex transactions.

    The Importance of Benchmarking and Load Testing

    Shopify didn't assume MySQL would work—they proved it with months of rigorous testing. If you're considering a similar migration, don't skip this step. Test with realistic traffic patterns, not just synthetic benchmarks.

    Designing for Concurrency with Row-Level Locking

    If you're using a relational database for high-concurrency workloads, make sure you're using InnoDB (or equivalent) with row-level locking. Design your schema so that transactions touch as few rows as possible, and keep transactions short.

    Redis Is Still Valuable

    Shopify didn't eliminate Redis from their stack entirely. They still use it for caching and other use cases where its strengths shine. The migration was specifically about the inventory reservation system, not a wholesale rejection of Redis.

    Key Takeaway: The best engineers don't have favorite tools—they have a toolbox. Redis and MySQL are both excellent, but they excel at different jobs. Know the difference and choose accordingly.


    Conclusion: Rethinking Database Choices for High-Scale Systems

    Shopify's migration from Redis to MySQL for inventory reservations challenges a lot of assumptions about what "scalable" means. For years, the conventional wisdom was that in-memory stores like Redis are the only way to handle massive scale. Shopify proved that a well-designed relational database can not only handle the load but do it with stronger consistency guarantees and less operational complexity.

    The seven key takeaways:

    1. Redis as a primary store creates hidden operational costs and consistency challenges.
    2. MySQL's ACID transactions provide the consistency guarantees that inventory systems need.
    3. Reservation tokens are an elegant pattern for modeling complex inventory logic in a relational database.
    4. Sub-10ms latency at 1M+ requests per second is achievable with MySQL when designed properly.
    5. Zero-downtime migrations are possible with careful canary deployment strategies.
    6. Reducing moving parts improves reliability and simplifies maintenance.
    7. Choose tools based on use case, not hype—Redis and MySQL both have their place.

    This migration has broader implications beyond e-commerce. Any system that relies on in-memory stores for critical data should ask: "Am I trading consistency for speed I don't actually need?" Sometimes the answer will be yes, and that's fine. But sometimes, like Shopify discovered, the relational database you already have is the better choice.


    FAQ

    Why did Shopify replace Redis with MySQL for inventory reservations?

    Shopify replaced Redis because using it as a primary data store for inventory required custom sharding and replication logic, created consistency challenges in high-concurrency scenarios, and added significant operational overhead. MySQL provided ACID transactions and row-level locking out of the box, which simplified the system while improving consistency.

    Did Shopify completely abandon Redis?

    No. Shopify still uses Redis for caching and other use cases where its strengths are a better fit. The migration was specifically for the inventory reservation system, not a company-wide ban on Redis.

    How does MySQL handle high concurrency for inventory reservations?

    MySQL with the InnoDB storage engine uses row-level locking, which allows concurrent transactions on different rows to proceed without blocking each other. Shopify also designed their reservation system to use short-lived transactions and optimistic locking where appropriate.

    Was there any downtime during the migration?

    No. Shopify used a canary deployment strategy, starting with 1% of traffic and gradually increasing to 100% over several weeks. They monitored continuously and ensured merchant experience was unaffected throughout.

    Is MySQL faster than Redis for this use case?

    For this specific use case, MySQL achieved sub-10ms latency at over 1 million requests per second—comparable to Redis. More importantly, MySQL provided stronger consistency guarantees, which was the primary goal of the migration.

    What are reservation tokens?

    Reservation tokens are unique identifiers that represent a specific quantity of stock for a specific SKU, tied to an order or cart. They allow the system to handle reservations, partial cancellations, and modifications atomically within database transactions.

    Does this mean Redis is not scalable?

    No. Redis is highly scalable for its intended use cases, like caching and ephemeral data. The issue was using Redis as a primary data store with strong consistency requirements, which is not what it was designed for.

    What lessons did Shopify share from this migration?

    Key lessons include: match the tool to the use case, benchmark and load test thoroughly before migrating, design for concurrency with row-level locking, and don't underestimate the value of operational simplicity.


    Want to dive deeper into Shopify's engineering decisions? Read the full case study on the Shopify Engineering Blog and share your thoughts on when you'd choose MySQL over Redis for your own systems.

    N
    Nina Okonkwo
    Technical Educator
    Taught 10,000+ students to code through bootcamps and online courses. Believes every skill can be taught if you break it down right. Based in Nairobi.

    📬 Get new articles by email

    No spam. Just new articles from Practical Guides.