Design a flash sale system
A hundred times the normal traffic for ten minutes and a thousand items: how to avoid overselling and still keep the site alive.
On the roadmap:Interview Ready · step 5: Real-world designs
Lesson 6 of 18 · 11 min read · quiz · exercise
The problem
A flash sale sells a small number of items at a special price for a short time. Traffic is spiky: 100x or more of normal load for a few minutes, mostly from people refreshing the page.
Requirements
- Never oversell: exactly the available quantity is sold.
- Stay up: the rest of the site must keep working.
- Be fair and resist bots.
- Fast feedback: users should quickly learn whether they got one.
Why the naive version fails
stock = db.read("phone") -- 1000 requests read 1
if stock > 0:
db.write("phone", stock-1) -- 1000 requests write 0
Many requests see stock = 1 at once, and every one of them "succeeds". The database is also hammered by half a million reads. Two separate problems: correctness (races) and load (spike).
Before: everyone hits the database
After: layers shed load first
What changed
- The CDN and edge absorb most of the clicks
- A fast counter decides who gets stock, not the database
- Orders are written at a pace the database can handle
Layered defence: shed load early
Figure SDA-RWS-06-1 · Flash sale: layers that shed load · © forcsguy.com
- CDN serves the sale page, images and scripts. Only the "buy" action reaches your servers.
- Edge protection: rate limit per user and IP, block known bots, require a challenge for suspicious clients.
- Waiting room: users get a place in line and are admitted at a controlled rate matching what checkout can take.
- Stock gate: an in-memory atomic counter (Redis
DECR, or a Lua script that checks and decrements together) answers "did you get one?" in microseconds, and rejects the rest at once. - Order queue: winners go onto a queue; the order service processes them at its own pace.
- Database is the final source of truth, using a conditional update (
UPDATE ... SET stock = stock - 1 WHERE stock > 0) so it can never go negative even if the gate misbehaves.
Image: Barry Bahler · Public domain · Source · Wikimedia Commons: FEMA - 37526 - Florida Logisitics Response center
Holds and payment
Payment takes time and can fail. When a user wins a slot:
- Create an order in a pending state and hold the item for a short time (for example 10 minutes).
- If payment succeeds, confirm the order. If the timer expires or payment fails, release the item back to the gate so waiting users can have it.
Correctness details
- Idempotency: an order request carries a unique key, so a double-click or retry never creates two orders.
- One per customer rules are checked at the gate with a per-user key.
- Do not trust the gate alone: if the cache loses data, the database constraint still prevents overselling.
- Reconcile counters with the database after the sale.
Operating it
- Pre-warm: scale servers and caches before the start time; do not rely on reactive auto-scaling to catch a spike that arrives in one second.
- Isolate: run the sale on its own stack or pool so it cannot take down the rest of the shop.
- Degrade gracefully: turn off recommendations and non-essential features during the sale.
- Load test beforehand with realistic bursts, and rehearse failure.
- Use a kill switch and a clear "sold out" state so users stop retrying.
Related reading
- Scaling Slack's Job QueueSlack Engineering · SlackCase Studies
- Build Your Own XCodeCrafters · GitHubGitHub
- Architectures of Finance, Banking, and Payment SystemsRedhat engineers · RedhatCase Studies
- Billing and Payment Platform at GrammarlyGrammarly engineers · GrammarlyCase Studies
Show 6 moreShow fewer
Check your understanding
Question 1 of 3
0 correct so far
Why is reading the stock from the database and then decrementing it in application code dangerous during a flash sale?
Go deeper
- Using load shedding to avoid overload by Amazon Builders' Library
Practise it: A flash sale starts
Everything below is already set up for this lesson: change the design, run the traffic, and see whether you meet the goal.
- 1The task
- 2Build and test
At the sale start, 8,000 requests per second hammer the same product pages.
Goal: Under 1% errors within $2,000 a month.
Where could a repeated answer be served before it reaches your servers?
Try it yourself
1,000 phones go on sale at noon and 500,000 people click at the same second. Explain the layers that stand between the click and the database, and how you guarantee exactly 1,000 orders.
Click what a strong design here would need:
More in Real systems
© 2026 forcsguy.com. Original lesson text and diagrams. Books and sites linked above belong to their authors.