Skip to main content

Design an Amazon Product Detail Page

Premium

You're asked to design an e-commerce product page like Amazon's. For a single product, the page shows the title, images, price, availability, delivery estimate, ratings, reviews, and recommendations. It should render in a few hundred milliseconds across a catalog of hundreds of millions of products and handle billions of page views per day.

Each section comes from a different service, often owned by a different team. The freshness requirements also vary. A product description can be an hour old without causing trouble, but the price must be correct when the shopper clicks buy. Let's separate those data paths instead of forcing every section to use the same freshness policy.

Clarify the requirements

  • What's on the page? Ask the interviewer to list the sections because they will define your service boundaries. Core product data, price, availability, reviews, and recommendations are a reasonable scope.
  • How fresh does each part need to be? Ask this for each section rather than for the page as a whole. The answer will shape most of your caching decisions.
  • Is the page personalized? Recommendations and delivery estimates usually are, so you cannot cache every part of the page globally.
  • How many products, and how skewed is traffic? A catalog of hundreds of millions where a few thousand products carry most views is a very different caching problem from uniform access.

Assume a catalog of 500M products, heavily skewed traffic, personalized recommendations, and separate freshness requirements for each section.

Back-of-envelope numbers

  • Page views: 2B/day25k/sec2\text{B/day} \approx 25\text{k/sec}, with peak-season spikes several times that
  • Materializing every page: 500M products×50 KB25 TB500\text{M products} \times 50\text{ KB} \approx 25\text{ TB}
  • Hot set, if the top 1% of products serve most views: 5M products×50 KB250 GB5\text{M products} \times 50\text{ KB} \approx 250\text{ GB}

The hot set determines the caching strategy. You do not need to hold all 25 TB in memory. Cache the hot 250 GB and assemble pages in the long tail on demand.

High-level architecture

live

live

Client

① Edge / CDN

② Page assembly service

③ Product read model

④ Pricing + inventory

⑤ Recommendations

⑥ Source services

⑦ Change events

⑧ Read model builder

Components
  1. Edge. Serves static assets and images, and can cache whole anonymous page fragments briefly.
  2. Page assembly service. Composes the response and owns the fan-out to its dependencies.
  3. Product read model. Holds the slow-changing sections in one denormalized document per product.
  4. Pricing and inventory. Always fetched live, never served from the read model.
  5. Recommendations. Personalized, fetched live, and safe to drop if slow.
  6. Source services. Catalog, reviews, seller, and media, each owned by a different team.
  7. Change events. Each source publishes when its data changes.
  8. Read model builder. Consumes those events and rebuilds the affected document.
A read model assembles the shared parts of the page ahead of time. Personalized and price-critical sections are fetched live and composed on top.

Deep dive 1: the denormalized read model

Avoid calling eight services on every request. The page has to wait for the slowest calls, and its availability becomes the product of all eight services' availability. If each dependency is 99.9% available, the composed page is available only about 99.2% of the time. That works out to roughly six hours of downtime per year caused by composition alone.

Precompute the slow-changing data instead. A read model is one denormalized document per product containing the title, description, images, specifications, seller information, aggregate rating, and top reviews. Build it ahead of time, store it by product ID, and fetch it with one lookup.

Maintain the read model with events. Each source service publishes a change event, and a builder consumes the event and rewrites the affected document. This is the "denormalized document maintained by events" case from the read-heavy pattern. Identify which team owns rebuilds when the read model drifts from its sources.

Deep dive 2: freshness per section, not per page

Assign each section its own freshness budget instead of applying one consistency model to the whole page:

  • Title, description, images, specs. Hours of staleness is fine. Serve entirely from the read model.
  • Ratings and review counts. Minutes. Read model, rebuilt on a rolling schedule.
  • Price. Seconds at most, and exact at checkout. Fetch it live, keep it out of the read model, and verify it again at add-to-cart and payment.
  • Availability and delivery estimate. Seconds, and personalized by location. Fetch live.
  • Recommendations. Personalized, and entirely optional. Fetch live with a tight timeout.

Deep dive 3: degrading gracefully

Some dependency will eventually fail, so decide how the page should behave when that happens.

Rank the sections by necessity. The product itself is required; without the read model, there is no page. Price and availability are required for the buy box, although you can briefly render a "checking availability" state. Recommendations, recently viewed items, and related products are optional.

Give each optional call a short timeout and a fallback, then render the page without that section if the timeout expires. If the recommendations service takes 800ms, the customer should see a page without its carousel rather than wait. State that tradeoff directly.

Use request coalescing when a popular product's read-model entry expires. Without it, thousands of concurrent requests may try to rebuild the same entry. Let one request perform the rebuild while the others wait or receive a stale copy. This applies stale-while-revalidate at the document level.

Deep dive 4: serving the long tail

The long tail is why you should not cache everything. With 500M products and a hot set of 5M, the other 495M receive little traffic. Caching them wastes memory without meaningfully improving the hit rate. Let those pages miss and assemble them on demand, accepting a slower first render. Make this an intentional two-tier policy.

At peak-season scale, the read-model cache is likely to run out of memory before CPU, which is why the hot-set calculation matters. Live price calls may become the page's bottleneck, so they need a dedicated and heavily provisioned path. A bulk catalog update can also create a rebuild storm, so rate-limit the event consumer to protect the builder.

Common pitfalls

  • Fanning out to every service on each request. Latency becomes the sum, availability becomes the product.
  • Caching price. The one field where staleness is a real-money error.
  • One freshness setting for the whole page. Either everything is too stale or nothing is cacheable.
  • No degradation plan. A slow optional service takes down a page that could have rendered fine without it.
  • Caching the entire catalog. Ignores that traffic is heavily skewed and memory is finite.

Leveling signals

Mid-levelIdentifies the page as read-heavy, puts a cache in front of a set of backing services, and separates static assets onto a CDN.
SeniorBuilds a denormalized read model maintained by change events, assigns freshness per section, keeps price live, and gives optional sections timeouts and fallbacks.
Staff+Sizes the hot set against the long tail and designs a deliberate two-tier caching policy. Reasons about composed availability across dependencies, and owns the rebuild and backfill path for the read model.
Design InstagramHard

Build a photo feed that assembles each user's timeline from the accounts they follow.

Design E-commerce CheckoutMediumPlanned

Take a cart through inventory reservation, payment, and order confirmation.