---
title: "How Shopify handled 1.27M requests per second in BFCM"
description: "System-design lessons from BFCM 2022: distribute load, protect the database, cache repeated reads and prepare for traffic spikes."
canonical: "https://tmtuan.dev/en/articles/shopify-bfcm-risk-mitigation"
language: "en"
image: "https://tmtuan.dev/_img/articles/shopify-bfcm-risk-mitigation/shopify-bfcm-risk-mitigation-cover.5b694078-og.jpg"
updated: "2026-10-10"
tokens: 3499
---

# How Shopify handled 1.27 million requests per second during Black Friday

Black Friday and Cyber Monday (BFCM) are among the most demanding periods for an ecommerce platform. For merchants, they are a sales opportunity. For the platform behind those stores, they are a test of how much traffic the infrastructure can absorb in a very short window.

This article is an edited version of Tom Smykowski's BFCM 2022 summary, published on December 2, 2022. The story shows the scale of the problem: Shopify handled about **1.27 million requests per second**, with close to 4.3 petabytes of data transferred each day. Yet the request count is not the whole story. The harder problem is protecting the components that can become bottlenecks, especially the database, while millions of people browse products, add items to carts, check out and pay.

## 1\. Black Friday tests infrastructure endurance

BFCM traffic is not only high; it can change sharply. A promotion, a popular product or the opening moment of a sale can create a large burst in seconds.

At platform scale, the system must remain available for many stores at once. That requires every layer, from network and application to the data layer, to be prepared for peak traffic rather than merely operating well at average load.

The important point is to examine the whole processing path. Adding capacity at one layer does not automatically remove the limit at another.

## 2\. The database is often the hardest bottleneck

Application servers can be scaled horizontally in a straightforward way: add instances, place a load balancer in front of them and distribute requests.

```mermaid
flowchart TD
    accTitle: Horizontally scaled application tier
    accDescr: A load balancer distributes incoming requests across several application servers. The diagram shows why the application layer can expand by adding instances.

    LB["Load balancer."] --> APP1["App 1."]
    LB --> APP2["App 2."]
    LB --> APP3["App 3."]

    classDef edge fill:#e8f1ff,stroke:#2563eb,color:#172554,stroke-width:2px;
    classDef app fill:#ecfdf5,stroke:#059669,color:#064e3b,stroke-width:2px;
    class LB edge;
    class APP1,APP2,APP3 app;
```

_Adding application servers expands capacity in the application layer, but it does not by itself remove limits in the data layer._

The problem appears when all application servers direct their requests to one database. More servers can process more business logic, but the system is still constrained if the database cannot handle the corresponding query volume.

```mermaid
flowchart LR
    accTitle: Database bottleneck
    accDescr: Several application servers send queries to one database. The database becomes the limiting point when the combined query volume exceeds its capacity.

    APP1["App 1."] --> DB[("Database.")]
    APP2["App 2."] --> DB
    APP3["App 3."] --> DB
    APP4["App 4."] --> DB
    APP5["App 5."] --> DB

    classDef app fill:#ecfdf5,stroke:#059669,color:#064e3b,stroke-width:2px;
    classDef data fill:#fff1f2,stroke:#e11d48,color:#881337,stroke-width:3px;
    class APP1,APP2,APP3,APP4,APP5 app;
    class DB data;
```

_Many application servers calling one database can turn the database into a bottleneck when query volume grows faster than its processing capacity._

During BFCM 2022, Shopify's MySQL fleet processed about **14 million queries per second**. It is a reminder of a core system-design principle: databases, caches, queues and other stateful dependencies are often harder to expand than the web tier. Scaling cannot begin and end with adding application servers.

## 3\. One million requests per second does not mean one server

No single server handles all 1.27 million requests per second. At this scale, work is spread across layers, each with a distinct responsibility:

- **Load balancers** distribute traffic.
- **Application servers** run business logic.
- **Cache services** serve repeatedly read data.
- **Specialised services** handle distinct workload types.
- **The data layer** stores and processes durable data.
- **MySQL** receives queries that must reach stateful data.

```mermaid
flowchart TD
    accTitle: Conceptual ecommerce traffic flow
    accDescr: Internet traffic reaches a load balancer and a group of application servers. Frequently read data can be served from cache services, while data that must be read or written goes to the data layer and MySQL.

    INTERNET["Internet."] --> LB["Load balancer."]
    LB --> APPS["Application servers."]
    APPS --> CACHE["Cache services."]
    APPS --> DATA["Data layer."]
    CACHE --> DATA
    DATA --> MYSQL[("MySQL.")]

    classDef edge fill:#e8f1ff,stroke:#2563eb,color:#172554,stroke-width:2px;
    classDef app fill:#ecfdf5,stroke:#059669,color:#064e3b,stroke-width:2px;
    classDef data fill:#fff1f2,stroke:#e11d48,color:#881337,stroke-width:3px;
    class INTERNET,LB edge;
    class APPS,CACHE app;
    class DATA,MYSQL data;
```

_A conceptual traffic flow from the article: cache serves repeated reads before requests need to reach the application and data layers._

The goal is not for every request to reach MySQL. The goal is for only the requests that need source data or need to change state to continue down to the data layer.

## 4\. Cache is an important protection layer

Consider a popular product page read one million times while the product changes only a few times a minute. Querying the database for every page view makes the database repeat the same work unnecessarily.

A cache handles most of that pattern:

- **Cache hit:** return the result immediately without a database query.
- **Cache miss:** the request must reach the database for data.

This reduces database CPU, database I/O, network traffic and query latency. It also helps a system tolerate bursts when many people read catalog data, product details, store configuration or other infrequently changing data.

Cache does not replace the database, however. Operations that require correct state or change state still need careful handling in the data layer.

## 5\. Not every request has the same importance

A system built for high load cannot handle every request in the same way.

Read requests such as product views, store configuration and image delivery are often suitable for caching or a CDN. Checkout, order creation and payments, on the other hand, have side effects. They cannot be cached as simply as a read.

That makes it important to distinguish:

- Read-heavy and write-heavy workloads.
- Stateless and state-changing requests.
- Work that needs an immediate response and work that can be processed asynchronously.

Separating less important or deferrable work preserves capacity for the flows that need the most protection.

## 6\. Scaling means more than adding servers

Imagine a system with 10 application servers and one database. Raising the application fleet to 100 servers does not help much if the database can still process only a limited number of queries.

Scaling must be viewed as a pipeline: client, CDN, load balancer, application, cache and asynchronous processing, then the database.

Each layer needs enough capacity for the work it receives. The right design question is not just how much CPU or RAM remains on a server. It is where the next bottleneck is and how to reduce pressure on it.

## 7\. Peak traffic must be prepared for in advance

BFCM has one important advantage: the date is known. That allows teams to prepare capacity planning, load testing, monitoring, alerting, database capacity, infrastructure capacity and disaster recovery early.

A system should not wait until traffic peaks to react. Preparation gives the team time to find bottlenecks, set alert thresholds and test critical flows under heavy load before the real event.

## 8\. The greatest danger is traffic arriving together

A system may handle one million requests per second under ordinary conditions and still fail when that one million requests arrive **at the same instant**. The danger lies in the traffic shape, not only in the total request count.

Imagine a promotion beginning exactly at **00:00:00**. At **23:59:59**, traffic is still low. One second later, many people click through at once, traffic spikes and the same resources receive concurrent pressure. That simultaneous burst can be far more dangerous than the same number of requests distributed over time.

```mermaid
flowchart LR
    accTitle: Traffic spike when a promotion begins
    accDescr: At 23 hours 59 minutes and 59 seconds traffic is low. When the promotion starts at midnight, a concurrent burst pushes many requests to the same dependency.

    T1["23:59:59.."] --> LOW["Low traffic.."] --> OPEN["Sale opens."] --> T2["00:00:00.."] --> SPIKE["Concurrent burst..."] --> PRESSURE["Same dependency pressure...."]

    classDef calm fill:#ecfdf5,stroke:#059669,color:#064e3b,stroke-width:2px,padding:16px;
    classDef event fill:#e8f1ff,stroke:#2563eb,color:#172554,stroke-width:2px,padding:16px;
    classDef spike fill:#fff7ed,stroke:#ea580c,color:#7c2d12,stroke-width:3px,padding:16px;
    classDef risk fill:#fff1f2,stroke:#e11d48,color:#881337,stroke-width:3px,padding:16px;
    class T1,LOW calm;
    class OPEN,T2 event;
    class SPIKE spike;
    class PRESSURE risk;
```

_The one-second transition from 23:59:59 to 00:00:00 can turn low traffic into a concurrent burst when a promotion begins. This is a concurrency problem, not only a requests-per-second problem._

A classic example is a cache that has just expired. Many requests miss the cache and all query the database. The database is overloaded, latency rises, requests time out and clients begin to retry. Retries create still more requests, turning the initial burst into a harmful loop.

```mermaid
flowchart TD
    accTitle: Thundering herd overload loop
    accDescr: A simultaneous cache miss sends many queries to the database. Overload increases latency, causes timeouts and retries, and retries create even more requests.

    MISS["Cache miss."] --> QUERIES["Many DB queries."]
    QUERIES --> OVERLOAD["Database overload."]
    OVERLOAD --> LATENCY["Latency increases."]
    LATENCY --> TIMEOUT["Timeouts."]
    TIMEOUT --> RETRY["Retries."]
    RETRY --> QUERIES

    classDef warning fill:#fff7ed,stroke:#ea580c,color:#7c2d12,stroke-width:2px;
    classDef danger fill:#fff1f2,stroke:#e11d48,color:#881337,stroke-width:3px;
    class MISS,QUERIES,LATENCY,TIMEOUT,RETRY warning;
    class OVERLOAD danger;
```

_A mass cache miss can form a loop: queries rise, the database overloads, timeouts appear and retries push traffic higher._

The problem is therefore not only having enough capacity. The system must also control how requests are distributed and prevent millions of them from reaching one limited dependency at once.

## 9\. A system needs controlled degradation

When traffic exceeds capacity, a system does not have to choose only between perfect operation and total failure.

Graceful degradation means reducing or temporarily disabling less important features, limiting certain request types, prioritising the most important traffic and ultimately protecting the database. In ecommerce, keeping checkout and order creation available is often more valuable than preserving every secondary feature at the same level.

The goal is to protect the database and flows with side effects while preserving the most important part of the customer experience under pressure.

## 10\. Lessons to apply

The important lesson from BFCM is not only the number of 1.27 million requests per second. It is how a large system divides work and avoids concentrating all load on one bottleneck.

When designing for high traffic:

- Scale the application layer horizontally where appropriate.
- Use cache for frequently read, slowly changing data.
- Clearly separate read, write, stateless and state-changing workloads.
- Protect the database and other hard-to-scale dependencies.
- Plan capacity before a peak event.
- Use observability to follow bottlenecks, not only CPU and RAM.
- Design graceful degradation for overload conditions.

## Conclusion

The BFCM story shows that scaling is not simply about adding servers. It is about finding the real bottleneck and designing the workload so it does not pile up there.

Application servers can be scaled horizontally relatively easily. Databases, caches, networks, queues and other stateful systems more often determine the real limit. For Shopify, the challenge is greater because millions of merchants must keep operating their stores during the most important period of the year. When designing for millions of requests, start with the question: **where will the next bottleneck be?**

## Structured data (JSON-LD)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Article","@id":"https://tmtuan.dev/en/articles/shopify-bfcm-risk-mitigation#article","headline":"How Shopify handled 1.27 million requests per second during Black Friday","description":"System-design lessons from BFCM 2022: distribute load, protect the database, cache repeated reads and prepare for traffic spikes.","datePublished":"2026-10-10","dateModified":"2026-10-10","inLanguage":"en","url":"https://tmtuan.dev/en/articles/shopify-bfcm-risk-mitigation","mainEntityOfPage":"https://tmtuan.dev/en/articles/shopify-bfcm-risk-mitigation","image":"https://tmtuan.dev/_img/articles/shopify-bfcm-risk-mitigation/shopify-bfcm-risk-mitigation-cover.5b694078-og.jpg","author":{"@type":"Person","@id":"https://tmtuan.dev/#person","name":"Tran Manh Tuan","url":"https://tmtuan.dev/en"}},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://tmtuan.dev/en"},{"@type":"ListItem","position":2,"name":"Articles","item":"https://tmtuan.dev/en/articles"},{"@type":"ListItem","position":3,"name":"How Shopify handled 1.27 million requests per second during Black Friday","item":"https://tmtuan.dev/en/articles/shopify-bfcm-risk-mitigation"}]}]}
```
