System Design Interview: Design an E-Commerce Platform (Amazon / Shopify)

System Design Interview: Design an E-Commerce Platform (Amazon / Shopify)

An e-commerce platform handles product discovery, inventory management, order processing, and payment — all while maintaining consistency under high concurrent load during sales events. This guide covers the architecture used by Amazon and Shopify, with emphasis on the inventory, ordering, and search systems that interviewers focus on.

Requirements

Functional: browse and search products (catalog), manage product inventory, add to cart, checkout with payment, track orders, handle returns and refunds, manage seller listings (marketplace model).

Non-functional: 100M active users, 1M orders/day, search results in <200ms, no overselling (inventory consistency), 99.99% checkout availability.

Core Services

1. Product Catalog Service

products(id, title, description, brand, category_id, seller_id, status)
product_variants(id, product_id, sku, size, color, price, images)
categories(id, parent_id, name, path)  -- tree structure

The product catalog is read-heavy and write-rarely. Cache product data in Redis (TTL 5 minutes) and Elasticsearch for search. When a product is updated, invalidate the Redis cache and re-index in Elasticsearch asynchronously via Kafka.

2. Inventory Service

Inventory is the hardest part — preventing overselling under concurrent purchases:

inventory(sku_id, warehouse_id, quantity_available, quantity_reserved)

-- Reserve inventory at checkout (atomic):
UPDATE inventory
SET quantity_reserved = quantity_reserved + :qty,
    quantity_available = quantity_available - :qty
WHERE sku_id = :sku AND warehouse_id = :wh
  AND quantity_available >= :qty;  -- only succeeds if stock available
-- Returns 0 rows updated = out of stock → fail checkout

-- Commit on order completion:
UPDATE inventory SET quantity_reserved = quantity_reserved - :qty
WHERE sku_id = :sku AND warehouse_id = :wh;

-- Release on checkout abandonment or cancellation:
UPDATE inventory SET quantity_reserved = quantity_reserved - :qty,
                     quantity_available = quantity_available + :qty
WHERE sku_id = :sku;

The single conditional UPDATE is atomic in PostgreSQL. No separate lock needed for the common case. Reservations expire after 30 minutes if checkout is not completed (background job releases them).

3. Search Service (Elasticsearch)

Product search must handle full-text, faceted filtering, and ranking:

GET /products/_search {
  "query": {
    "bool": {
      "must": [{"multi_match": {"query": "running shoes", "fields": ["title^3", "description", "brand^2"]}}],
      "filter": [
        {"term":  {"category": "footwear"}},
        {"range": {"price": {"gte": 50, "lte": 150}}},
        {"term":  {"in_stock": true}}
      ]
    }
  },
  "sort": [{"_score": "desc"}, {"sales_rank": "asc"}],
  "aggs": {
    "brands":    {"terms": {"field": "brand"}},
    "price_ranges": {"range": {"field": "price", "ranges": [...]}}
  }
}

Boost fields: title (3x), brand (2x), description (1x). Sort by relevance score then sales rank. Aggregations power the filter sidebar (brand, price, rating, color).

4. Cart Service

Shopping carts are ephemeral and session-bound. Store in Redis (Hash type, key: cart:{session_id}):

HSET cart:session_abc sku_123 2  # 2 units of sku_123
HSET cart:session_abc sku_456 1
EXPIRE cart:session_abc 86400    # expire after 24 hours of inactivity

# Cart contents:
HGETALL cart:session_abc → {sku_123: 2, sku_456: 1}

On checkout: transfer cart to a pending order record in PostgreSQL, then clear the Redis cart.

5. Order Service

Order state machine: PENDING → CONFIRMED → PROCESSING → SHIPPED → DELIVERED | CANCELLED | RETURNED

Each state transition is an event published to Kafka. Notification Service sends emails/SMS. Fulfillment Service picks and ships. Billing Service captures payment on CONFIRMED.

Flash Sale Architecture

Product launches (PS5 restock, limited sneakers) create massive concurrent demand:

  • Queue on high-demand items: virtual waiting room with Redis queue (same as Ticketmaster pattern)
  • Pre-warm inventory cache: cache inventory count in Redis, decrement on each purchase. Only hit PostgreSQL on cache miss or for final commit.
  • Dedicated flash sale service: isolate flash sale inventory checks from regular checkout to prevent cascading failures

Multi-Seller Marketplace

For marketplace (Amazon, Shopify Plus), multiple sellers list the same product:

  • Offer model: product_id + seller_id + price + quantity = an offer. Buy Box selects the best offer (price + shipping + seller rating).
  • Seller inventory: each seller manages their own inventory. Fulfillment can be seller-managed (FBM) or platform-managed (FBA).
  • Commission: platform takes 5-20% commission per sale, tracked in a separate financial ledger.

Interview Tips

  • Lead with the inventory reservation pattern — the conditional UPDATE preventing overselling is the key technical question
  • Explain the catalog/inventory separation: catalog is read-heavy + cacheable; inventory requires strong consistency
  • For search: Elasticsearch with multi_match boosting and aggregations is the standard answer
  • The cart in Redis (ephemeral) vs. order in PostgreSQL (persistent) is an important design distinction
  • For flash sales: describe the virtual waiting room rather than brute-force scaling

  • Coinbase Interview Guide
  • Uber Interview Guide
  • Airbnb Interview Guide
  • DoorDash Interview Guide
  • Stripe Interview Guide
  • Shopify Interview Guide
  • {
    “@context”: “https://schema.org”,
    “@type”: “FAQPage”,
    “mainEntity”: [
    {
    “@type”: “Question”,
    “name”: “How do you prevent overselling inventory in an e-commerce system?”,
    “acceptedAnswer”: { “@type”: “Answer”, “text”: “Use an atomic conditional UPDATE: UPDATE inventory SET quantity_available = quantity_available – qty, quantity_reserved = quantity_reserved + qty WHERE sku_id = ? AND quantity_available >= qty. If quantity_available drops below qty, the WHERE clause fails and 0 rows are updated – the checkout fails immediately with "out of stock." No separate lock is needed because the UPDATE is atomic in PostgreSQL. On checkout completion, decrement quantity_reserved. On cart abandonment (30-minute timeout), release the reservation: add qty back to quantity_available and subtract from quantity_reserved. A background job handles expired reservations. This two-column approach (available + reserved) lets you track in-flight inventory without risk of overselling.” }
    },
    {
    “@type”: “Question”,
    “name”: “How does Elasticsearch power e-commerce product search?”,
    “acceptedAnswer”: { “@type”: “Answer”, “text”: “E-commerce search uses Elasticsearch multi_match with field boosting: title gets 3x weight, brand 2x, description 1x. Boolean filters narrow results: category, price range, in_stock status. Aggregations compute facets (counts by brand, size, color, price range) to power the filter sidebar in a single query. Ranking: combine relevance score (BM25 from match quality) with business signals (sales rank, sponsored items, in-stock preference). Product catalog data is maintained in the primary database (PostgreSQL) as source of truth; a Kafka consumer syncs updates to Elasticsearch within seconds. Synonyms (sneakers=shoes), spell correction, and stemming are configured in the Elasticsearch analyzer to handle natural language queries.” }
    },
    {
    “@type”: “Question”,
    “name”: “How do you design a shopping cart in an e-commerce system?”,
    “acceptedAnswer”: { “@type”: “Answer”, “text”: “Shopping carts are ephemeral and session-bound – they are not permanent data. Store in Redis using Hash type: key = cart:{session_id}, field = sku_id, value = quantity. Redis HSET for add-to-cart, HINCRBY for quantity changes, HDEL to remove items. Set TTL to 24 hours (reset on each modification). Benefits: sub-millisecond access, automatic expiration, no database load for cart updates. On checkout: read the full cart with HGETALL, validate each SKU against current inventory and pricing (prices can change), create a pending order in PostgreSQL, then DEL the Redis cart. Guest carts (no login): associate with session ID cookie. On login: merge the guest cart with any existing cart for that user account.” }
    }
    ]
    }

    Scroll to Top