Headless Commerce
Rebuilt a regional retailer's storefront as a headless Next.js app with an edge-cached BFF, taking checkout from a 4.1s LCP to under 1.5s during peak sale traffic.
- Next.js
- Node.js
- Redis
- PostgreSQL
The problem
The legacy storefront was a server-rendered monolith. Every promotion caused cache stampedes on the product API, checkout timed out under load, and the marketing team waited on deploys for copy changes.
Constraints
- Zero downtime cut-over during the busiest quarter
- Prices and stock must never be stale at checkout
- Arabic and English with full RTL support
- Existing ERP stays the source of truth
Architecture
Key decisions
Product content renders as cached Server Components with tag-based revalidation. Price and stock stream in through a tiny client island backed by the BFF.
Trade-off: Two fetch paths per page to reason about, in exchange for a fully cacheable shell.
Concurrent misses for the same SKU share one in-flight promise and one Redis write, which ended the stampedes during flash sales.
Trade-off: A slow upstream call now delays every waiting request, so it sits behind a 300ms timeout and a stale fallback.
Cart, address, payment and confirmation are explicit states with typed transitions, which made retries and back-button behaviour predictable.
Trade-off: More upfront modelling than a set of form pages.
In the code
1const inflight = new Map<string, Promise<Product>>();23export async function getProduct(sku: string): Promise<Product> {4 const cached = await redis.get(`product:${sku}`);5 if (cached) return JSON.parse(cached);67 // Collapse concurrent misses into a single upstream call.8 let pending = inflight.get(sku);9 if (!pending) {10 pending = withTimeout(erp.fetchProduct(sku), 300)11 .then(async (product) => {12 await redis.set(`product:${sku}`, JSON.stringify(product), "EX", 60);13 return product;14 })15 .finally(() => inflight.delete(sku));16 inflight.set(sku, pending);17 }18 return pending;19}What I learned
- Cache invalidation got easy once each piece of data had exactly one owner.
- Load tests against production-like data found more issues than any review.