7 Key Takeaways from One of the Most Surprising Database Migrations in E-Commerce
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.
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.
When you use Redis as your source of truth, you inherit a set of problems:
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.
Why MySQL? Shopify already had deep operational experience with MySQL across their platform. But more importantly, MySQL provides something Redis doesn't: ACID transactions.
Redis, by contrast, offers eventual consistency at best when used as a primary store with replication. For inventory, that's a dangerous trade-off.
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.
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.
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.
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:
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;
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.
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.
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.
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.
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.
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.
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.
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.
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.
One of the most underrated benefits of this migration is the reduction in operational complexity.
Previously, Shopify operated a dedicated Redis cluster for inventory reservations. That meant managing:
All of that went away. The reservation system now runs on MySQL, which Shopify already operated at scale across their platform.
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.
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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
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.
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.
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.
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.