Headless Commerce: Next.js Storefront Dev Guide
Build a headless commerce storefront with Next.js. API-first architecture, Shopify Hydrogen alternative, and performance optimization techniques.
Lighthouse score (headless Next.js)
Smaller JS bundle vs. traditional
Conversion lift per 100ms faster
Build time for 10K product catalog
Key Takeaways
Headless commerce decouples the frontend storefront from the backend commerce engine, giving developers full control over the user experience while delegating inventory, payments, and order management to purpose-built APIs. Next.js 15 with the App Router is the dominant frontend framework for headless storefronts in 2026 — combining React Server Components, streaming SSR, and static generation into a cohesive architecture optimized for commerce performance.
This guide walks through building a production-grade headless storefront from architecture decisions through deployment, with specific code patterns for the most common implementation challenges.
Headless Commerce Architecture
A headless commerce architecture separates concerns across three distinct layers: the frontend presentation layer, the commerce API layer, and the data layer. Each layer can evolve independently, allowing teams to upgrade or swap components without rebuilding the entire stack.
Presentation Layer
Next.js 15 (App Router, RSC, Streaming)
Server-rendered HTML, client-side interactivity, routing, SEO
Hosting: Vercel, Cloudflare Pages, AWS CloudFront
Commerce API Layer
Shopify Storefront API / Medusa.js / BigCommerce
Products, inventory, cart, checkout, customers, orders
Hosting: Shopify cloud / self-hosted (Medusa) / managed
CMS Layer (optional)
Sanity, Contentful, Payload, or Shopify metaobjects
Editorial content, landing pages, promotional banners, blog
Hosting: Cloud-hosted SaaS or self-hosted
Search Layer (optional)
Algolia, Meilisearch, or Shopify Predictive Search
Instant search, faceted filtering, product recommendations
Hosting: SaaS or self-hosted
Our eCommerce solutions service covers full headless storefront development — from API integration through CDN deployment and ongoing performance monitoring.
Next.js App Router Setup
The App Router (stable since Next.js 13.4, recommended for all new projects since Next.js 14) introduces React Server Components as the default rendering model. For commerce, this means product pages, collection listings, and search results render server-side with zero client JavaScript for the static content — only interactive elements like the cart button and product image carousel ship client code.
Recommended Project Structure
/app
├── (store)/
│ ├── layout.tsx # Store layout (header, cart, footer)
│ ├── page.tsx # Homepage (featured products, hero)
│ ├── products/
│ │ ├── page.tsx # Product listing (SSG + search params)
│ │ └── [handle]/
│ │ └── page.tsx # Product detail (SSG via generateStaticParams)
│ ├── collections/
│ │ └── [handle]/
│ │ └── page.tsx # Collection pages (SSG)
│ └── cart/
│ └── page.tsx # Cart review (dynamic, auth optional)
├── (checkout)/
│ └── checkout/
│ └── page.tsx # Checkout (dynamic, client components)
└── api/
├── cart/route.ts # Cart mutations (Server Actions preferred)
└── revalidate/route.ts # ISR revalidation webhook endpointRendering Strategy by Page Type
| Page | Strategy | Revalidation | Rationale |
|---|---|---|---|
| Product Detail | SSG + ISR | On product.update webhook | High traffic, changes infrequently |
| Collection Listing | SSG + ISR | 300s or on collection.update | Shared across many visitors |
| Search Results | Dynamic SSR | N/A (user-specific query) | Unique per query string |
| Cart | Client-side | Real-time via state | User-specific, needs instant updates |
| Checkout | Dynamic SSR | N/A | Sensitive data, no caching |
| Order Confirmation | Dynamic SSR | N/A | User-specific, post-payment |
Product Catalog API
The Shopify Storefront API uses GraphQL, which allows you to request exactly the product fields you need — no over-fetching. Below are the essential queries for product pages and collection listings.
// Product detail query (Shopify Storefront API)
const PRODUCT_QUERY = `
query ProductByHandle($handle: String!, $country: CountryCode)
@inContext(country: $country) {
product(handle: $handle) {
id
title
description
seo { title description }
variants(first: 100) {
nodes {
id
title
availableForSale
price { amount currencyCode }
compareAtPrice { amount currencyCode }
selectedOptions { name value }
}
}
images(first: 10) {
nodes { url altText width height }
}
metafields(identifiers: [
{ namespace: "custom", key: "size_guide" }
]) { value type }
}
}
`;// generateStaticParams for product pages
export async function generateStaticParams() {
const products = await shopify.request(ALL_PRODUCT_HANDLES_QUERY, {
variables: { first: 250 },
});
// Returns up to 250 products per request — paginate for larger catalogs
return products.products.nodes.map((p) => ({ handle: p.handle }));
}
export const revalidate = false; // Static until revalidated by webhookCart & Checkout Flow
Cart state is the most complex client-side feature in a headless storefront. The cart must persist across page navigations, survive browser refresh, handle optimistic updates for instant feedback, and stay synchronized with the commerce backend's actual inventory and pricing.
Cart Architecture
- Cart items array (id, quantity, variant)
- Cart total (optimistic calculation)
- Loading states for mutations
- Persisted to localStorage (cart ID)
- addItem / removeItem / updateQuantity actions
- cartCreate: initialize cart on first add
- cartLinesAdd: add products to cart
- cartLinesUpdate: update quantities
- cartLinesRemove: remove line items
- cartBuyerIdentityUpdate: apply customer context
Checkout Strategy
For Shopify-backed stores, redirect to Shopify's hosted checkout via the cart.checkoutUrl. This is the recommended approach — Shopify Checkout handles payment processing, tax calculation, shipping rate retrieval, discount codes, and order creation. Building a custom checkout is only warranted for Shopify Plus merchants who need custom checkout UI or non-Shopify payment processors.
Payment Integration
Payment integration options depend on your commerce backend. For Shopify-backed stores, you have three options; for custom backends, direct Stripe integration is the standard approach.
| Approach | When to Use | Complexity | PCI Scope |
|---|---|---|---|
| Shopify Hosted Checkout | Shopify backend, standard checkout flow | Low (redirect only) | SAQ A (minimal) |
| Shopify Custom Checkout (Plus) | Shopify Plus, custom checkout UI needed | Medium (checkout extensibility API) | SAQ A |
| Stripe Elements | Custom backend (Medusa, custom API) | Medium | SAQ A-EP |
| Stripe Checkout (hosted) | Custom backend, fastest implementation | Low | SAQ A |
For Stripe-specific implementation details — webhook handling, subscription billing, and error recovery — see our Stripe payment integration developer guide.
Performance Optimization
Performance is the primary business justification for headless commerce. These optimizations deliver the most measurable impact on Core Web Vitals and conversion rates.
- Use next/image with Shopify CDN as remotePattern
- Serve AVIF with WebP fallback (Shopify CDN supports both)
- Set priority prop on above-fold hero/product images
- Use sizes prop matching your CSS breakpoints
- Lazy load product gallery images (default behavior)
- Default to Server Components — only add 'use client' for interactivity
- Lazy import heavy client components (product image zoom, reviews)
- Use next/dynamic with ssr: false for below-fold interactive components
- Avoid large client-side libraries (prefer server-side alternatives)
- Measure bundle with @next/bundle-analyzer before and after changes
- Fetch product data in Server Components — avoids client waterfall
- Use React cache() to deduplicate identical requests within a render
- Pre-fetch collection data on hover with prefetch prop on Link
- Cache Shopify API responses with unstable_cache (tag-based)
- Implement stale-while-revalidate patterns for collection pages
- Use next/font for zero-layout-shift font loading
- Subset fonts to latin characters only (reduces font file 70-80%)
- Inline critical CSS for above-fold content
- Use Tailwind CSS v4 (single CSS file, no runtime overhead)
- Avoid CSS-in-JS libraries that add runtime overhead
Deployment
Vercel is the optimal deployment platform for Next.js headless storefronts — it was built by the Next.js team and has first-class support for all App Router features including RSC, Server Actions, and ISR webhooks. Cloudflare Pages (via the OpenNext adapter) is a strong alternative for teams prioritizing edge latency globally.
| Platform | Pros | Cons | Est. Cost (10K visits/day) |
|---|---|---|---|
| Vercel | Best Next.js support, preview URLs, ISR webhooks | Can be expensive at scale; vendor lock-in | $20–$150/mo |
| Cloudflare Pages | Fastest global edge, $0 egress, Workers integration | OpenNext adapter required; some features unsupported | $0–$25/mo |
| AWS (ECS/Lambda) | Full control, existing AWS infrastructure | Significant DevOps overhead; slower iteration | $30–$200/mo |
Ready to build your headless storefront?
Our web development team builds production-grade headless commerce storefronts with Next.js, optimized for Core Web Vitals and conversion performance.
Frequently Asked Questions
Related Guides
Continue exploring web development and eCommerce architecture.