Design an E-Commerce Platform like Amazon

HardE-Commerce & PaymentsMicroservicesInventorySagaSearch

Problem

Design an online store. Customers search and browse a catalog of 500 million products, add items to a cart, and check out with payment. The system must never sell more units than are in stock, even during flash sales, and customers must track their orders through shipping and delivery. The store has 300 million active customers and processes 10 million orders per day, with sales events that bring 10 times normal traffic.

  • Do third-party sellers list products, or only the store itself?
  • Is stock tracked per warehouse, and do we choose which warehouse fulfills an order?
  • Should carts persist across devices and for logged-out users?
  • How long can an item be held in a cart or during checkout before stock is released?
  • What payment methods are required, and is a split payment (gift card plus card) needed?
  • Are product reviews and recommendations in scope?

Items in bold are existing requirements. The rest are suggestions. Confirm with the interviewer whether they are relevant first.

  • Search and browse products with filters, and view product detail pages.
  • Add, update, and remove items in a persistent cart.
  • Check out: reserve inventory, charge payment, and create an order.
  • Prevent overselling under concurrent purchases.
  • Track order status from placement through delivery.
  • Support cancellations and returns with refunds.
  • Show accurate prices, including promotions, at checkout.

Items in bold are existing requirements. The rest are suggestions. Confirm with the interviewer whether they are relevant first.

  • 10 million orders per day, about 115 per second on average and over 1,000 per second during sales.
  • Browse traffic is about 100 times orders: roughly 100,000 page views per second at peak.
  • Inventory must be strongly consistent per item and warehouse; no overselling.
  • Product pages under 200 ms at p99; checkout under 2 seconds.
  • 500 million products with an average of 10 KB of metadata is about 5 TB, plus images on a CDN.
  • High availability for browse and cart; checkout can degrade by queueing but must never lose a paid order.

The platform is split into services along business boundaries: catalog, search, cart, pricing, inventory, order, payment, and fulfillment. The browse path is read-heavy and served from caches, a CDN, and a search index fed from the catalog. Checkout is a saga coordinated by the order service: reserve inventory with conditional updates, authorize payment, then confirm, with compensating actions that release stock or void payment if a later step fails.

Loading diagram...

Browse and search. Product pages are assembled from the catalog (title, images, attributes), pricing, and a cached availability flag. Static parts are cached at the CDN. Search queries go to the search index, which is updated from catalog change events within minutes.

Add to cart. The cart service writes (cart_id, product_id, quantity) to the cart store. Carts for logged-out users are keyed by a cookie id and merged into the user's cart at login. Adding to the cart does not reserve stock.

Check out. The client submits the cart with an idempotency key. The order service creates a PENDING order with prices from the pricing service, then asks inventory to reserve each line with a 15-minute hold. Next it authorizes payment. If both succeed, the order becomes CONFIRMED, the reservations are committed, and an OrderConfirmed event is published. If payment fails, the reservations are released and the order is marked FAILED.

Fulfill. The fulfillment service picks a warehouse for each line, sends pick requests, and updates the order as items ship, publishing tracking events. When the order ships, the payment is captured.

Source of truth for product information.

  • A document store such as DynamoDB or MongoDB for flexible product attributes; images in object storage behind a CDN.

Data Model

  • products(product_id, seller_id, title, description, category_path, attributes_json, image_urls, status, updated_at)
  • variants(product_id, sku, attributes_json) for size and color combinations.

Scalability

Partition by product id. Product pages are read millions of times and updated rarely, so a read-through cache serves nearly all reads. Every change publishes an event to the bus for search and other consumers.

Tradeoffs

A document model fits products whose attributes vary widely by category (a laptop and a shirt share almost nothing). A relational schema would need either sparse columns or an entity-attribute-value table, both awkward at this scale.

Full-text and faceted search across the catalog.

  • Elasticsearch or OpenSearch with per-category facets, plus a learning to rank model trained on clicks and purchases.

API

  • GET /search?q=&category=&filters=&sort=&cursor= returns products with facet counts.

Scalability

The index is sharded by product id and replicated; replicas are added before sales events. Query results for popular searches are cached for a short time.

Tradeoffs

Stock in search results is a cached flag updated from inventory events, so a result can say "in stock" seconds after the last unit sold. Checkout re-checks stock authoritatively, which is cheaper than querying inventory for every search hit.

Stores each customer's cart durably and across devices.

  • A highly available key-value store such as DynamoDB, keyed by cart id.

API

  • GET /cart
  • PUT /cart/items/:sku with { quantity }
  • DELETE /cart/items/:sku

Scalability

Each cart is an independent small document, so the store partitions perfectly. Writes are frequent but tiny.

Tradeoffs

The cart favors availability over consistency: if two devices update it concurrently, the store merges by item (keeping the latest quantity per item). Losing an "add to cart" costs a sale, while a duplicate item is easy for the customer to fix.

Tracks stock per SKU per warehouse and prevents overselling.

  • A strongly consistent relational database (PostgreSQL or Aurora) sharded by SKU.

Diagram

Loading diagram...

Data Model

  • stock(sku, warehouse_id, available, reserved, version)
  • reservations(reservation_id, order_id, sku, warehouse_id, quantity, expires_at, status)

Scalability

The reserve step is one conditional update (UPDATE stock SET reserved = reserved + q WHERE sku = ? AND available - reserved >= q), so most SKUs never contend. For flash sales on a single hot SKU, stock is split into several sub-counters across rows, and a request tries a random sub-counter first, spreading lock contention.

Tradeoffs

Reserving at checkout rather than at add-to-cart avoids locking stock in abandoned carts while still guaranteeing that a paid order has its units. Expiring reservations ensure crashed checkouts give stock back automatically.

Coordinates checkout as a saga and owns order state.

  • PostgreSQL sharded by customer id; the transactional outbox pattern for publishing events; a workflow engine for retries and compensation.

API

  • POST /orders with { cartId, addressId, paymentMethodId, idempotencyKey } returns { orderId, status }.
  • GET /orders/:id returns status, items, and tracking.
  • POST /orders/:id/cancel.

Data Model

  • orders(order_id, customer_id, status, total, currency, address_json, idempotency_key, created_at)
  • order_lines(order_id, sku, quantity, unit_price, reservation_id, shipment_id)

Scalability

During sales, checkout requests that exceed capacity are placed in a queue with a waiting page, protecting inventory and payment from overload. The idempotency key makes client retries safe.

Tradeoffs

A saga with compensating steps avoids a distributed transaction across inventory, payment, and orders, which would hold locks across services and fail whenever any participant is slow. The cost is temporary intermediate states, which the order status exposes as "processing".

Authorizes, captures, and refunds payments.

  • External payment processors with tokenized cards; an internal ledger recording every money movement.

Scalability

Calls to the processor carry idempotency keys derived from the order id, so retries never double charge. Captures run asynchronously when items ship.

Tradeoffs

Authorizing at checkout and capturing at shipment matches what is charged to what is actually sent, which matters for partial shipments and cancellations. The ledger is append-only, so every refund is a new entry rather than an edit, giving a full audit trail.

Related questions