Design an E-Commerce Platform on AWS
A worked system-design example for a full e-commerce platform on AWS — product catalog, cart, checkout, inventory, and order processing, tying together nearly every service category covered elsewhere in this course.
Want a visual for this topic?
Generate a diagram tailored to Design an E-Commerce Platform on AWS — the AI picks whichever visual (architecture, flowchart, ER diagram, etc.) best fits this specific AWS concept.
Sign in to generate a visual →🎓 Learning objectives
- •Map each major e-commerce component (catalog, cart, checkout, inventory, orders) to an appropriate AWS service
- •Explain why inventory decrement needs strong consistency while product browsing doesn't
- •Design the checkout flow to handle payment processing failures gracefully
- •Identify where asynchronous, event-driven processing fits versus where synchronous consistency is required
What is it?
An e-commerce platform's AWS system design combines multiple distinct sub-problems, each mapped to the AWS service best suited to its specific access pattern: a heavily-cached, read-optimized product catalog (CloudFront, ElastiCache/DAX in front of a database), a strongly-consistent inventory and checkout flow (DynamoDB conditional writes or RDS transactions) to prevent overselling, a saga-style payment/reservation flow to handle payment failures without leaving inventory incorrectly held, and an asynchronous, event-driven order-processing pipeline (SNS/SQS/EventBridge) for everything that happens after a confirmed order.
Why it exists
This layered design exists because e-commerce genuinely combines multiple different problems with fundamentally different correctness and performance requirements in one product — a single one-size-fits-all architecture (either treating everything as needing strong consistency, which would be too slow/expensive for catalog browsing, or treating everything as eventually consistent, which would allow overselling) fails one half of the requirements, forcing the layered, per-component approach.
Problem it solves
It solves building an e-commerce platform that can handle massive, read-heavy, spiky browsing traffic cheaply and quickly, while still guaranteeing strong consistency exactly where it's actually required (inventory decrement, payment) to prevent overselling or double-charging, and processing everything after order confirmation asynchronously so customer-facing checkout latency stays low regardless of downstream system load.
Intuition
The single biggest design insight for e-commerce specifically: not every part of the system needs the same consistency and latency guarantees — ruthlessly separating 'this must be strongly consistent and synchronous' (inventory decrement, payment) from 'this can be eventually consistent and asynchronous' (everything else) is what lets the system be both correct where it matters and fast/scalable everywhere else.
Analogy
An e-commerce platform is like a well-run department store: the sales floor (catalog browsing) is designed for huge crowds to wander freely with minimal friction, but the actual cash register transaction (checkout/inventory decrement) requires a precise, one-at-a-time, strongly-consistent handoff to make sure two people can't both walk out with the store's last unit of the same item.
Technical explanation
A DynamoDB conditional write for inventory reservation (UpdateItem with ConditionExpression: availableQuantity >= :requestedQuantity) atomically checks-and-decrements in a single operation, guaranteeing that concurrent checkout attempts for the same limited-stock item can't both succeed past the actual available quantity, without needing separate application-level locking. The saga pattern's compensating action (releasing a reservation on payment failure) needs to be implemented as its own reliable step — often itself an idempotent operation triggered by a payment-failure event — since a naive 'just decrement, then increment back on failure' approach is vulnerable to the process crashing between those two steps, which is why production implementations typically track reservation state explicitly (e.g., a separate 'reserved' versus 'confirmed' quantity) rather than mutating a single raw stock count directly.
Architecture
A CDN (CloudFront) and cache layer (ElastiCache/DAX) sit in front of the product catalog's underlying database, serving the large majority of browsing traffic without touching the origin database for popular items. The checkout flow performs a strongly-consistent inventory reservation (a conditional DynamoDB write, or an RDS transaction) followed by a payment-gateway authorization call using an idempotency key; on success, the order record is created and an OrderPlaced event is published to SNS, fanning out to independent SQS-queue-backed consumers for fulfillment/warehouse system integration, email confirmation (SES), and analytics — each processing asynchronously and independently, decoupled from the synchronous checkout path and from each other.
Workflow
- Product catalog data is served from a heavily cached read path (CloudFront for static/semi-static content, ElastiCache/DAX in front of the underlying catalog database) to handle high, read-skewed browsing traffic cheaply. 2) On checkout, the system attempts a strongly-consistent inventory reservation (a conditional DynamoDB write decrementing available stock only if sufficient stock exists) before attempting payment. 3) A payment authorization call is made (with an idempotency key to prevent double-charging on retry); on success, the reservation is confirmed as a real decrement and the order is created; on failure, the reservation is released back. 4) An
OrderPlacedevent is published to SNS/EventBridge, fanning out asynchronously to fulfillment (via SQS), confirmation email (via SES, per the notification-system pattern), and analytics pipelines. 5) None of the post-confirmation fan-out steps block the customer's checkout response.
Example
A shopper browses a heavily-cached product catalog page served largely from CloudFront/ElastiCache; adding an item to their cart and proceeding to checkout triggers a strongly-consistent inventory reservation in DynamoDB, followed by a payment authorization call — on success, the order is confirmed and an OrderPlaced event is published to SNS, fanning out asynchronously to fulfillment, email confirmation, and analytics systems, none of which the shopper had to wait for.
Real-world usage
Every major production e-commerce platform follows some version of this layered consistency approach — aggressive caching for catalog/browsing, strongly-consistent reservation logic for inventory/checkout, and asynchronous event-driven fan-out for order fulfillment and downstream processing — and this is one of the most commonly asked comprehensive system-design interview questions specifically because it requires demonstrating judgment about where consistency truly matters versus where it doesn't.
Trade-offs
Reserving inventory before payment confirmation (rather than decrementing only after payment succeeds) avoids overselling during the payment-processing window, at the cost of needing a compensating release action if payment ultimately fails — real added complexity, but necessary to avoid the far worse alternative of confirmed sales for out-of-stock items. Heavy caching of the catalog trades perfect real-time accuracy (a cached product page might briefly show slightly stale stock/price info) for the massive scale and speed needed to handle read-heavy browsing traffic — acceptable because checkout itself always re-validates against the strongly-consistent inventory source before finalizing a sale.
Visual explanation
Picture a large retail store with a busy, open sales floor (catalog, heavily cached, high traffic, low friction) leading to a small number of tightly-controlled checkout counters (inventory reservation + payment, strongly consistent, one careful transaction at a time) — and once a sale completes at the counter, a separate back-office team (asynchronous fan-out) independently handles shipping, receipt printing, and updating the store's sales records, none of which makes the next customer in line wait any longer.
Advantages
- —
Aggressive catalog caching (CloudFront/ElastiCache/DAX) handles massive, read-skewed browsing traffic cheaply without touching the strongly-consistent inventory path at all
- —
Reserve-then-confirm inventory handling prevents overselling even under concurrent checkout attempts for the same limited-stock item
- —
Asynchronous, event-driven post-order processing (fulfillment, email, analytics) keeps the customer-facing checkout response fast and decoupled from downstream system health
- —
Idempotency keys on payment calls prevent double-charging a customer if a checkout request is retried due to a network blip
Disadvantages
- —
Running genuinely different consistency models for different parts of the same system (strongly-consistent inventory versus eventually-consistent catalog cache) adds real architectural complexity compared to a single uniform data-access pattern
- —
The saga-style reserve-then-confirm-or-release inventory pattern requires careful compensating-action logic to avoid leaving stock incorrectly held if a failure happens mid-flow (e.g., the process crashes between payment success and order confirmation)
- —
Cache invalidation for catalog data (price changes, stock updates reflected in cached pages) needs deliberate handling to avoid showing customers meaningfully stale information
- —
A large number of independent asynchronous post-order consumers (fulfillment, email, analytics, and potentially more) each need their own monitoring and dead-letter-queue handling to catch silent processing failures
Common mistakes
- —
Applying the same consistency model (either fully strong or fully eventual) to both catalog browsing and inventory decrement, when each actually needs a different approach
- —
Decrementing inventory permanently before payment is confirmed successful, risking incorrect stock levels if payment ultimately fails and no compensating release logic exists
- —
Making post-order processing (email, analytics, fulfillment notification) synchronous within the checkout request, adding unnecessary latency and coupling checkout success to unrelated downstream systems' availability
- —
Not using an idempotency key on payment authorization calls, risking a double charge if a checkout request is retried after a network timeout that actually succeeded server-side
In the AWS Console
- 1
DynamoDB → Tables → Create table
Create a DynamoDB table for inventory with a conditional-write-friendly schema (item ID as partition key, available-quantity attribute).
- 2
ElastiCache → Create cluster (or DynamoDB → DAX clusters → Create cluster)
Set up ElastiCache or DAX in front of the catalog data source for cached reads.
- 3
SNS → Topics → Create topic, then SQS → Queues → Create queue, subscribing from the topic
Create the SNS topic and SQS-queue subscriptions for post-order asynchronous fan-out.
🎤 Interview questions
Why might product catalog browsing use a different consistency model than checkout/inventory decrement? (Listen for: catalog browsing is read-heavy, tolerant of very slight staleness, and benefits from aggressive caching (CloudFront, DAX, ElastiCache) for speed and scale; inventory decrement during checkout needs strong consistency to avoid overselling — two customers shouldn't both successfully purchase the last unit of an item — which usually means a strongly-consistent DynamoDB conditional write or a transactional RDS operation specifically for the inventory-decrement step, even while the rest of the catalog uses eventually-consistent, cached reads)
How would you design the checkout flow to handle a payment failure gracefully, without leaving inventory incorrectly decremented? (Listen for: use a saga-style pattern — reserve inventory (a conditional decrement or a separate 'reserved' count) BEFORE attempting payment, attempt payment, and either confirm the reservation (on payment success) or release it back (on payment failure/timeout) via a compensating action; never permanently decrement inventory before payment is confirmed successful, and use idempotency keys on the payment call to avoid double-charging on a retried request)
What parts of this system would you make asynchronous/event-driven versus synchronous? (Listen for: the checkout request itself (inventory check/reservation, payment authorization) needs to be synchronous since the customer is waiting for a definite success/failure result; everything AFTER a confirmed order — sending confirmation emails, updating analytics, triggering fulfillment/warehouse systems, updating recommendation models — fits an asynchronous, event-driven pattern (an OrderPlaced event fanned out via SNS/EventBridge) since none of those need to block the customer's checkout response)
How would you scale the product catalog for a flash sale where a huge spike of traffic hits a small number of product pages? (Listen for: aggressive CloudFront caching of catalog pages/API responses, DynamoDB Accelerator (DAX) or ElastiCache in front of the catalog database for cache-aside reads, and considering pre-warming caches ahead of a known flash-sale start time — the read-heavy, highly-skewed-toward-a-few-hot-items nature of a flash sale is a caching problem more than a database-scaling problem)
Why would you use SQS between order placement and fulfillment/warehouse processing instead of calling the fulfillment system directly and synchronously? (Listen for: decoupling via a queue means a temporary fulfillment-system outage or slowdown doesn't fail or delay the customer-facing checkout response — orders queue up and get processed once fulfillment recovers, and the queue also naturally smooths out traffic spikes so the fulfillment system sees a steady processing rate rather than the full burst of a flash sale)