Chaturmind
LearnDSASystem DesignBlogPremium
Sign inGet started
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML

Company

  • Blog
  • Premium
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


System Design›Design E-Commerce Checkout & Inventory at Scale
Amazon / E-Commerce

Design E-Commerce Checkout & Inventory at Scale

e-commerceinventoryconcurrencyflash-saleconsistency

Problem Statement

Design the checkout and inventory system for a large e-commerce platform — accurately tracking stock across a massive, frequently-changing catalog while handling flash-sale-level concurrent demand for the same items without overselling.

Requirements

Functional

  • ✓Show accurate (or near-accurate) stock availability on product pages
  • ✓Reserve inventory during checkout, confirm on successful payment, release on abandonment
  • ✓Handle checkout: cart → address/payment → order confirmation, integrating Payment System
  • ✓Support flash sales / high-demand drops without overselling

Non-Functional

  • ✓Never oversell — reserved stock must be strictly consistent under concurrent demand
  • ✓Product browsing must stay fast even though inventory changes constantly
  • ✓Handle extreme concurrent demand spikes for a small number of hot items (flash sales)

Capacity Estimation

Capacity Estimation

  • Normal browsing: 50M DAU, product page views dominate (read-heavy, 100:1 or higher read:write ratio) — this path should be cached aggressively (Caching Strategies), since perfectly fresh stock counts aren't critical for casual browsing.
  • Flash sale scenario: a single popular item with 10,000 units available might see 500,000 concurrent checkout attempts in the opening seconds — a 50:1 oversubscription ratio on ONE inventory record, the specific hot-key/hot-partition problem named in Failure Scenario Walkthroughs, requiring deliberate handling distinct from normal-load design.

High-Level Architecture

Architecture

[Product Page] → [Product Service] (cached, eventually-consistent stock display)

[Checkout] → [Cart Service] → [Inventory Reservation Service] → [Payment System]
                                        │
                                        ▼
                              [Inventory DB] (strongly consistent for the reservation itself)

Two different consistency models coexist deliberately in the same system: the PRODUCT PAGE'S displayed stock count can be slightly stale (cached, eventually consistent — a customer seeing "12 in stock" when it's actually 10 is a minor, acceptable inconsistency), while the actual RESERVATION at checkout time must be strongly consistent (two customers must never both successfully reserve the last unit). Recognizing that different parts of the same system can and should make different consistency tradeoffs is a core System Design Interview Playbook skill (see CAP theorem's discussion in HLD Fundamentals Refresher).

Inventory reservation as a short-lived hold (not an immediate decrement)

Add to cart / begin checkout → RESERVE 1 unit (decrement available, increment reserved)
  with a TTL (e.g. 15 minutes)
Payment succeeds → CONFIRM reservation (reserved → sold, permanent)
Payment fails / cart abandoned / TTL expires → RELEASE reservation (reserved → available again)

This mirrors the authorize/capture separation from Payment — Core Flow directly: a reservation is a temporary hold, not a final commitment, letting the system recover cleanly (release the stock back) if the customer never completes checkout — without this, stock would be either oversold (no reservation at all) or permanently locked up by abandoned carts (immediate, non-expiring decrement).

Flash sale handling

For extreme, predictable demand spikes on specific items, standard mitigations include: a virtual waiting room / queue in front of checkout (smoothing the request rate rather than letting all 500,000 requests hit the reservation system simultaneously), and pre-partitioning the hot item's stock count across multiple shards/counters (splitting 10,000 units into, say, 10 counters of 1,000 each, reducing contention on any single counter) — directly applying Failure Scenario Walkthroughs' hot-key mitigation to a concrete inventory scenario.

API Design

API

GET /api/v1/products/{id}
→ 200 { "id": "prod_1", "price": 2999, "stockDisplay": "IN_STOCK" }  (cached, approximate)

POST /api/v1/cart/{cartId}/reserve
Body: { "productId": "prod_1", "quantity": 1 }
→ 200 { "reservationId": "res_1", "expiresAt": "..." }
→ 409 { "error": "OUT_OF_STOCK" }

POST /api/v1/checkout/{cartId}/complete
→ triggers Payment System charge → on success, confirms all reservations in the cart

Database Design

Data Model

inventory
  productId, totalStock, reservedStock, soldStock,
  availableStock = totalStock - reservedStock - soldStock   (computed, or maintained atomically)

reservations
  id, cartId, productId, quantity, status (ACTIVE/CONFIRMED/RELEASED), expiresAt

The reservation decrement must be an ATOMIC conditional update (UPDATE inventory SET reservedStock = reservedStock + 1 WHERE productId = ? AND availableStock >= 1), checked and applied as one database operation — a naive read-then-write (check available, then separately update) reintroduces the exact race condition idempotency/atomic-operation discussions elsewhere in this course exist to prevent (see Payment — Idempotency Implementation's check-then-insert race for the same underlying pattern).

Scaling Strategy

Product browsing scales via standard read-heavy patterns: caching (Caching Strategies), read replicas, and a CDN for static product assets. Inventory reservation for NORMAL-demand items scales by sharding inventory records across database shards (by productId). Inventory reservation for HOT items (flash sales) needs the additional counter-splitting/waiting-room mitigations above, since sharding by productId alone still leaves one specific hot product's record as a single contention point.

Trade-offs

  • Eventually-consistent product-page stock display vs strongly-consistent reservation: accepting staleness on the display (cheap, fast, cacheable) while paying for strong consistency only at the actual reservation moment (rare relative to page views) is a deliberate, favorable tradeoff — enforcing strong consistency on EVERY product page view would be far more expensive for no real correctness benefit, since a stale display number causes no actual overselling by itself.
  • Reservation TTL length: too short frustrates legitimate slow checkouts (release stock from under an actively-checking-out customer); too long lets abandoned carts hold stock hostage during high demand — 10-15 minutes is a common, reasonable default, sometimes shortened further specifically during flash sales.
  • Waiting room vs first-come-first-served with no queue: a waiting room adds real complexity and a perceived-unfair experience (a queue position) but protects the reservation system from being overwhelmed; for less extreme demand spikes, a simpler atomic-decrement-with-409-on-failure may be sufficient without a full waiting room.

Bottlenecks

A single hot product's inventory record during a flash sale is the canonical bottleneck this design has to handle explicitly — every other part of the system (browsing, cart, payment) can scale via standard horizontal patterns, but one row representing one product's stock count cannot be sharded away without the counter-splitting technique described above, since correctness requires all reservation attempts to ultimately agree on the same remaining-stock number.

Failure Scenarios

Payment fails after a reservation was made: the reservation must be explicitly released (not left dangling) — typically triggered both by the payment failure response itself AND, as a safety net, the reservation's own TTL expiry (mirroring the dead-letter/reconciliation safety-net pattern from Payment — Failure Handling & Reconciliation).

The reservation service itself is briefly unavailable during a flash sale: failing closed (reject new checkout attempts with a clear retry message) is correct here, unlike a rate limiter's typical fail-open default — accepting a checkout that can't actually verify/reserve stock risks the exact overselling this design exists to prevent.

Two concurrent requests for the last unit: the atomic conditional update in the database (not application-level locking) is what guarantees only one of the two requests succeeds — this is the same atomicity principle as Payment — Idempotency Implementation's database-level unique constraint, applied to a decrement instead of an insert.