System Design: Design Amazon E-Commerce — Product Catalog, Shopping Cart, Order Processing, Inventory, Search

Amazon processes millions of orders daily across hundreds of millions of products. Designing an e-commerce platform tests your ability to handle product catalogs, shopping carts, inventory management, order processing, and recommendation — each a complex system on its own. This guide covers the architecture of the core e-commerce components for system design interviews.

Product Catalog

The product catalog stores hundreds of millions of products with rich attributes: title, description, images, price, category, brand, dimensions, weight, seller, ratings, reviews, and product-specific attributes (clothing: size/color; electronics: specifications). Data model: a base product table with common fields + an attributes table for variable product-specific fields (Entity-Attribute-Value pattern or JSONB column). Product variations: a “T-shirt” product has variations (size S/M/L, color red/blue). Each variation has its own SKU, price, inventory, and images. The parent product page shows all variations; the user selects options. Storage: PostgreSQL for the relational catalog (product hierarchy, categories, sellers). Elasticsearch for product search (full-text search on titles and descriptions, faceted filtering by category/brand/price/rating). Redis for hot product data (pricing, availability — read millions of times per second). Read path: the product detail page loads data from Redis cache (product info, price, availability) with Elasticsearch for related products. Cache miss falls through to PostgreSQL. Write path: sellers update products via an admin API. Changes are written to PostgreSQL, then asynchronously propagated to Elasticsearch and Redis via CDC (Debezium).

Shopping Cart

The shopping cart must be: fast (sub-100ms for add/remove/view), persistent (survives browser close and device switching), and eventually consistent (a user adds an item on mobile, sees it on desktop within seconds). Architecture: (1) For logged-in users: store the cart in DynamoDB or Redis. Key: user_id. Value: list of (product_id, quantity, added_at). DynamoDB provides durability; Redis provides speed. Use both: Redis as the primary store (fast reads/writes), DynamoDB as the durable backup (async persist from Redis). (2) For guest users: store the cart in a browser cookie or localStorage. On login, merge the guest cart with the user cart (union of items, keeping the higher quantity for duplicates). Cart operations: addItem(product_id, quantity) — check product exists and is in stock (fast pre-check against Redis inventory). updateQuantity(product_id, quantity). removeItem(product_id). getCart() — return all items with current prices and availability. Price updates: the cart always shows the current price at checkout time, not the price when the item was added. If the price changed, show a notification. Inventory check: at cart view time, check availability. Show “Only 3 left” warnings. At checkout, re-verify and reserve inventory.

Inventory Management

Inventory must be exact — overselling creates customer dissatisfaction and operational costs (cancellations, refunds). Two-phase approach: (1) Soft reservation — when the user starts checkout, reserve the items for 10 minutes (decrement available_count, increment reserved_count). If the user completes payment, convert to a hard reservation (sold). If the user abandons checkout, release the reservation after timeout (increment available_count, decrement reserved_count). (2) Atomic decrement — for flash sales with extreme concurrency, use Redis DECR for the fast path: DECR inventory:{product_id}. If the result is >= 0, the reservation succeeded. If < 0, the item is out of stock (INCR to restore). Redis handles thousands of concurrent decrements per second on a single key. The database is the authoritative source (PostgreSQL with row-level locking). Redis is the fast layer for availability checks and flash sale contention. Reconciliation: periodically compare Redis counts with database counts. Fix discrepancies (caused by crashes between Redis DECR and database update). Multi-warehouse: inventory is distributed across fulfillment centers. Available inventory for a user = sum of inventory across warehouses that can ship to the user address within the delivery window.

Order Processing

Order lifecycle: (1) Order creation — user clicks “Place Order.” The order service creates an order record (status: PENDING), reserves inventory, and initiates payment. (2) Payment — the payment service charges the user payment method (see our Payment System guide for idempotency and double-charge prevention). On success: order status -> PAID. On failure: release inventory, status -> PAYMENT_FAILED. (3) Fulfillment — the order is routed to the nearest fulfillment center with the required items. Workers pick, pack, and ship. Status -> SHIPPED with tracking number. (4) Delivery — carrier delivers the package. Status -> DELIVERED. (5) Post-delivery — return window (30 days). If the user initiates a return: status -> RETURN_INITIATED -> RETURNED -> REFUNDED. This is a saga pattern: each step is a local transaction. Failure at any step triggers compensating transactions (cancel payment, release inventory). The order service is the saga orchestrator. Event-driven: each status change publishes an event to Kafka. Downstream services consume: notification service (sends email/push at each status change), analytics (tracks conversion, delivery time), and the recommendation engine (purchased items influence future recommendations).

Product Search and Recommendations

Product search: Elasticsearch indexes all products. Query processing: (1) Parse the query (spell correction, synonym expansion). (2) Retrieve candidates matching the query terms. (3) Rank by: text relevance (BM25 on title, description, brand), sales rank (popular products first), availability (in-stock products first), price competitiveness, seller rating, and personalization (user browsing and purchase history). (4) Apply facet filters (category, brand, price range, rating, Prime eligibility). (5) Return paginated results with facet counts. Autocomplete: suggest product names, categories, and brands as the user types (trie or Elasticsearch completion suggester). Recommendations: “Customers who bought this also bought” — collaborative filtering on purchase history. “Frequently bought together” — association rules from order basket analysis. “Recommended for you” — personalized ranking based on browsing history, purchase history, and wishlist. The recommendation pipeline runs offline (Spark) and the results are served from a pre-computed cache (Redis/DynamoDB) per user. Real-time signals (current browsing session) are blended at serving time to adjust recommendations based on immediate intent.

Scroll to Top