This is a practical guide for engineering teams not a hello-world tutorial. We cover the architectural decisions that matter for real commerce: rendering strategy, cart state management, authentication, webhook handling, and performance optimisation.
Project Architecture Overview
A Commerce Engine + Next.js storefront has four primary layers:
Next.js application: Pages, components, API routes, and rendering logic
Commerce Engine SDK: Type-safe client for all Commerce Engine API operations
State layer: Cart state, user session, wishlist (Zustand or React Context)
Edge layer: CDN, edge caching, and middleware (Vercel Edge Network or Cloudflare)
Setting Up the Commerce Engine Client
The Commerce Engine SDK wraps the REST API with full TypeScript support. Initialise the client once and export it for use across your application:
Create a single client instance in lib/commerce.ts, initialising with your storefront API key and region. The client exposes typed methods for every commerce operation: products, categories, cart, checkout, orders, and customer accounts.
Use separate API keys for server-side operations (with elevated permissions for order management) and client-side operations (read-only storefront permissions). Never expose your server-side API key in client-rendered code.
Product Listing Pages: ISR for Scale
Product listing pages (PLPs) are the highest-traffic pages on most storefronts. They should be fast, crawlable, and reflect catalogue changes quickly.
ISR with a 60-second revalidation window is the recommended pattern for PLPs on Commerce Engine storefronts. The page is statically generated at build time, cached at the CDN edge, and regenerated in the background when a request arrives after the revalidation window.
In your Next.js page, implement getStaticProps to fetch categories and products from Commerce Engine at build time. Set the revalidate option to 60 seconds. This gives you static performance with near-real-time catalogue updates — without the overhead of SSR on every request.
Product Detail Pages: SSR for Price Accuracy
Product detail pages (PDPs) require real-time price and availability accuracy. A customer who sees a price on a PDP and then sees a different price in cart has had a trust-damaging experience. For this reason, PDPs should be server-rendered on every request.
In your PDP page component, implement getServerSideProps to fetch the specific product from Commerce Engine on each request. This guarantees that every visitor sees current pricing and inventory status.
The SEO impact of SSR on PDPs is positive: the fully rendered product content — including price, availability, and description — is present in the initial HTML response that Googlebot crawls.
Cart State Management
Cart state is the most complex state in a commerce storefront. It must:
Persist across page navigation within a session
Be recoverable across browser sessions (persisted to Commerce Engine, not just localStorage)
Reflect real-time inventory and pricing from Commerce Engine
Update optimistically (immediate UI feedback) while validating server-side
The recommended pattern: store the Commerce Engine cart ID in a cookie. On every page load, fetch the cart from Commerce Engine using the stored cart ID. Display the server cart as the source of truth — not a locally cached version.
For cart mutations (add item, update quantity, remove item), use optimistic updates: update local state immediately for instant UI feedback, then make the Commerce Engine API call. If the API call fails (e.g., item is out of stock), roll back the local state and show an error.
Authentication and Customer Accounts
Commerce Engine customer authentication uses JWT tokens. The authentication flow:
Customer submits email/password on your login page
Your Next.js API route forwards credentials to Commerce Engine's auth endpoint
Commerce Engine returns an access token and a refresh token
Store the access token in an httpOnly cookie (never in localStorage)
Include the access token in the Authorisation header for all authenticated API calls
For Next.js, implement authentication token handling in middleware, not in individual page components. This ensures a consistent authentication state across all pages without repeating auth logic.
Webhook Handling for Real-Time Updates
Commerce Engine emits webhooks for catalogue changes (product.updated, inventory.updated) that your storefront needs to react to. Implement webhook handlers as Next.js API routes:
Create an API route at pages/api/webhooks/commerce-engine.ts (or app/api/webhooks/route.ts in App Router). Verify the webhook signature on every incoming request using your webhook secret. Process the event asynchronously — respond with 200 immediately and handle the event in the background.
Common webhook handlers in a Next.js Commerce Engine storefront:
Performance Optimisation
Image Optimisation
Commerce Engine product images should be served through Next.js Image component with automatic format conversion (WebP/AVIF), responsive sizing, and lazy loading. Configure your Commerce Engine CDN domain in next.config.js remotePatterns.
API Response Caching
Not all Commerce Engine API responses need to be fetched fresh on every request. Category structures change infrequently — cache the categories API response at the edge for 5 minutes. Product descriptions change less often than prices — consider separate cache TTLs for static content versus pricing data.
Edge Middleware for Personalisation
Use Next.js Edge Middleware for lightweight personalisation that runs before page rendering: geolocation-based currency selection, A/B test assignment, and authentication redirects. Edge Middleware runs at CDN edge with sub-millisecond execution — it adds no meaningful latency.
Deployment Architecture
Conclusion
Building a production headless storefront with Next.js and Commerce Engine is a well-trodden path — but the architectural decisions matter. Choosing the right rendering strategy for each page type, managing cart state server-side rather than client-side, handling webhooks for real-time updates, and optimising API caching are what separate performant, reliable storefronts from brittle prototypes.
Commerce Engine's API design is built to support these patterns. The result — a Next.js storefront that is fast for users, crawlable for search engines, and maintainable for engineering teams — is the definitive modern commerce stack.