LLM Docs Header: All requests to https://llm-docs.commercengine.io must include the Accept: text/markdown header (or append .md to the URL path). Without it, responses return HTML instead of parseable markdown.
Next.js Patterns
For basic setup, see setup/ .
Impact Levels
-
CRITICAL - Breaking bugs, security holes
-
HIGH - Common mistakes
-
MEDIUM - Optimization
References
Reference Impact
references/server-vs-client.md
CRITICAL - storefront(cookies()) vs storefront()
references/token-management.md
HIGH - Cookie-based token flow in Next.js
Mental Model
The storefront() function adapts to the execution context:
Context Usage Token Storage
Client Components storefront()
Browser cookies
Server Components storefront(cookies())
Request cookies
Server Actions storefront(cookies())
Request cookies (read + write)
Root Layout storefront({ isRootLayout: true })
Memory fallback
Build time (SSG) storefront()
Memory (no user context)
Setup
- Install
npm install @commercengine/storefront-sdk-nextjs
- Create Config
// lib/storefront.ts export { storefront } from "@commercengine/storefront-sdk-nextjs";
- Root Layout
// app/layout.tsx import { StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client"; import { storefront } from "@/lib/storefront";
// Root Layout has no request context — use isRootLayout flag const sdk = storefront({ isRootLayout: true });
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body> <StorefrontSDKInitializer /> {children} </body> </html> ); }
- Environment Variables
.env.local
NEXT_PUBLIC_STORE_ID=your-store-id NEXT_PUBLIC_API_KEY=your-api-key NEXT_BUILD_CACHE_TOKENS=true # Faster builds with token caching
Key Patterns
Server Component (Data Fetching)
// app/products/page.tsx import { storefront } from "@/lib/storefront"; import { cookies } from "next/headers";
export default async function ProductsPage() { const sdk = storefront(cookies()); const { data, error } = await sdk.catalog.listProducts({ page: 1, limit: 20, });
if (error) return <p>Error: {error.message}</p>;
return ( <div> {data.products.map((product) => ( <div key={product.id}>{product.name}</div> ))} </div> ); }
Server Actions (Mutations)
// app/actions.ts "use server";
import { storefront } from "@/lib/storefront"; import { cookies } from "next/headers"; import { redirect } from "next/navigation";
export async function loginWithEmail(email: string) { const sdk = storefront(cookies());
const { data, error } = await sdk.auth.loginWithEmail({ email, register_if_not_exists: true, });
if (error) return { error: error.message }; return { otp_token: data.otp_token, otp_action: data.otp_action }; }
export async function verifyOtp(otp: string, otpToken: string, otpAction: string) { const sdk = storefront(cookies());
const { data, error } = await sdk.auth.verifyOtp({ otp, otp_token: otpToken, otp_action: otpAction, });
if (error) return { error: error.message }; redirect("/account"); }
export async function addToCart(cartId: string, productId: string, variantId: string | null) { const sdk = storefront(cookies());
const { data, error } = await sdk.cart.addDeleteCartItem( { id: cartId }, { product_id: productId, variant_id: variantId, quantity: 1 } );
if (error) return { error: error.message }; return { cart: data.cart }; }
Static Site Generation (SSG)
// app/products/[slug]/page.tsx import { storefront } from "@/lib/storefront";
// Pre-render product pages at build time export async function generateStaticParams() { const sdk = storefront(); // No cookies at build time const { data } = await sdk.catalog.listProducts({ limit: 100 });
return (data?.products ?? []).map((product) => ({ slug: product.slug, })); }
export default async function ProductPage({ params }: { params: { slug: string } }) { const sdk = storefront(); // No cookies for static pages const { data, error } = await sdk.catalog.getProductDetail({ product_id_or_slug: params.slug, });
if (error) return <p>Product not found</p>; const product = data.product;
return ( <div> <h1>{product.name}</h1> <p>{product.selling_price}</p> {/* AddToCartButton is a Client Component */} </div> ); }
Client Component
"use client";
import { storefront } from "@/lib/storefront";
export function AddToCartButton({ productId, variantId }: Props) { async function handleClick() { const sdk = storefront(); // No cookies in client components const { data, error } = await sdk.cart.addDeleteCartItem( { id: cartId }, { product_id: productId, variant_id: variantId, quantity: 1 } ); }
return <button onClick={handleClick}>Add to Cart</button>; }
SEO Metadata
Use Next.js generateMetadata with CE product fields for meta tags, Open Graph, and structured data:
// app/products/[slug]/page.tsx import { storefront } from "@/lib/storefront"; import type { Metadata } from "next";
export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> { const sdk = storefront(); // No cookies — metadata runs at build time for static pages const { data } = await sdk.catalog.getProductDetail({ product_id_or_slug: params.slug, });
const product = data?.product; if (!product) return { title: "Product Not Found" };
const image = product.images?.[0];
return { title: product.name, description: product.short_description, openGraph: { title: product.name, description: product.short_description ?? undefined, images: image ? [{ url: image.url_standard, alt: image.alternate_text ?? product.name }] : [], }, }; }
CE field → meta tag mapping:
Meta Tag CE Field
<title>
product.name
meta description
product.short_description
og:image
product.images[0].url_standard
og:image:alt
product.images[0].alternate_text
Canonical URL Build from product.slug
For category/PLP pages, use the category name and description from listCategories() . For search pages, use the search query.
Common Pitfalls
Level Issue Solution
CRITICAL Missing cookies() in Server Components Use storefront(cookies()) for user-specific data on the server
CRITICAL Auth in Server Components instead of Actions Auth endpoints that return tokens MUST be in Server Actions, not Server Components
HIGH Missing StorefrontSDKInitializer
Required in root layout for automatic anonymous auth and session continuity
HIGH Using cookies() in Client Components Client Components use storefront() (no cookies) — tokens managed via browser cookies
MEDIUM Slow builds Set NEXT_BUILD_CACHE_TOKENS=true for token caching during SSG
MEDIUM Root Layout missing isRootLayout flag Root Layout runs outside request context — use storefront({ isRootLayout: true })
See Also
-
setup/
-
Basic SDK installation
-
auth/
-
Authentication flows
-
cart-checkout/
-
Cart management
Documentation
-
Next.js Integration: https://www.commercengine.io/docs/sdk/nextjs-integration
-
Token Management: https://www.commercengine.io/docs/sdk/token-management
-
LLM Reference: https://llm-docs.commercengine.io/sdk/