ce-nextjs-patterns

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.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "ce-nextjs-patterns" with this command: npx skills add commercengine/skills/commercengine-skills-ce-nextjs-patterns

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

  1. Install

npm install @commercengine/storefront-sdk-nextjs

  1. Create Config

// lib/storefront.ts export { storefront } from "@commercengine/storefront-sdk-nextjs";

  1. 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> ); }

  1. 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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

ce-cart-checkout

No summary provided by upstream source.

Repository SourceNeeds Review
General

ce

No summary provided by upstream source.

Repository SourceNeeds Review
General

ce-auth

No summary provided by upstream source.

Repository SourceNeeds Review
General

ce-orders

No summary provided by upstream source.

Repository SourceNeeds Review