SSR/meta-framework patterns for Commerce Engine using @commercengine/storefront. Covers Next.js, TanStack Start, Astro, and SvelteKit with publicStorefront(), clientStorefront(), serverStorefront(), bootstrap, server functions/actions, pre-rendering, and cookie-based token management.
LLM Docs Header: All requests to
https://llm-docs.commercengine.iomust include theAccept: text/markdownheader (or append.mdto the URL path). Without it, responses return HTML instead of parseable markdown.
For basic installation, see setup/. For the rarer case where you need custom request-bound SSR bindings with @commercengine/ssr-utils (Nuxt or other unsupported frameworks), see ssr/.
This skill covers frameworks with first-party Commerce Engine wrappers: Next.js, TanStack Start, Astro, and SvelteKit. All ship as subpath exports of @commercengine/storefront.
| Reference | When to Use |
|---|---|
references/nextjs.md | CRITICAL - Next.js setup, accessor rules, Server Actions, SSG |
references/tanstack-start.md | CRITICAL - TanStack Start setup, server functions, route loaders, pre-rendering |
references/astro.md | CRITICAL - Astro setup, browser bootstrap, server-only cookie access |
references/sveltekit.md | CRITICAL - SvelteKit setup, load functions, hooks, form actions |
references/token-management.md | HIGH - Token flow, bootstrap pattern, cookie configuration |
All first-party SSR wrappers follow the same three-accessor pattern (Next.js, TanStack Start, Astro, SvelteKit):
| Accessor | Environment | Purpose |
|---|---|---|
publicStorefront() | Server or client | Build-safe public reads (catalog, categories, store config). API-key-backed, no session. |
clientStorefront() | Client only | Browser-side session client. Throws if called on server. |
serverStorefront() | Server only | Request-bound session with cookie-backed token storage. Next.js: await storefront.serverStorefront(). TanStack Start: serverStorefront() from server-only module. Astro: serverStorefront(Astro.cookies). SvelteKit: serverStorefront(cookies) in load/hooks/actions. |
SSR apps must call storefront.bootstrap() on the client (root layout mount) before later serverStorefront() reads depend on cookie continuity. Without it, session continuity is not guaranteed. See each framework's reference for the exact bootstrap pattern.
Use publicStorefront() in route loaders (TanStack Start) or generateStaticParams / Server Components (Next.js) to pre-render catalog pages. This gives you excellent SEO and fast initial page loads:
// Route loader (TanStack Start) or Server Component (Next.js)
const sdk = storefront.publicStorefront();
const { data } = await sdk.catalog.listProducts({ limit: 100 });
publicStorefront() never creates sessions, never reads/writes cookies, and is safe for build-time, pre-render, and ISR contexts.
Once the app is hydrated, client-side fetching is equally fast and much less complex. There is no need to wrap SDK calls in server functions — the SDK talks to a public API with no secrets to protect. Use React Query (or any fetching library) directly:
// Public reads — no session needed
const sdk = storefront.publicStorefront();
const { data } = await sdk.catalog.listProducts({ limit: 20 });
// Session-bound reads (cart, wishlist, account) — use client accessor
const sessionSdk = storefront.clientStorefront();
const { data: wishlist } = await sessionSdk.cart.getWishlist();
The session-aware overloads resolve user_id automatically — no manual ID passing needed.
| Framework | Import | Factory | Server Entry | Server Accessor | Env Prefix | Reference |
|---|---|---|---|---|---|---|
| Next.js | .../nextjs | createNextjsStorefront() | Built-in (async) | await storefront.serverStorefront() | NEXT_PUBLIC_ | references/nextjs.md |
| TanStack Start | .../tanstack-start | createTanStackStartStorefront() | .../tanstack-start/server | serverStorefront() | VITE_ | references/tanstack-start.md |
| Astro | .../astro | createAstroStorefront() | .../astro/server | serverStorefront(Astro.cookies) | PUBLIC_ | references/astro.md |
| SvelteKit | .../sveltekit | createSvelteKitStorefront() | .../sveltekit/server | serverStorefront(cookies) | PUBLIC_ | references/sveltekit.md |
All imports above are subpaths of @commercengine/storefront. See the framework-specific reference for full setup, accessor rules, patterns, and examples.
When using Hosted Checkout with an SSR framework, the Storefront SDK remains the session owner. Wire onTokensUpdated in the storefront config so checkout stays in sync on the client side:
// In storefront config (both frameworks)
onTokensUpdated: (accessToken, refreshToken) => {
if (typeof window !== "undefined") {
void import("@commercengine/checkout").then(({ getCheckout }) => {
getCheckout().updateTokens(accessToken, refreshToken);
});
}
},
Then initialize checkout in the bootstrap/initializer component after storefront.bootstrap() completes. No provider wrapper needed — initCheckout is called once and useCheckout() works globally.
Callback signature difference: The SDK's
onTokensUpdatedreceives two separate arguments(accessToken, refreshToken). Checkout'sonTokensUpdatedreceives a single object({ accessToken, refreshToken }). Do not mix these up.
useEffect(() => {
const init = async () => {
await storefront.bootstrap();
const sdk = storefront.clientStorefront();
const accessToken = await sdk.getAccessToken();
const refreshToken = await sdk.session.peekRefreshToken();
initCheckout({
storeId: /* ... */,
apiKey: /* ... */,
authMode: "provided",
accessToken: accessToken ?? undefined,
refreshToken: refreshToken ?? undefined,
onTokensUpdated: ({ accessToken, refreshToken }) => {
void sdk.setTokens(accessToken, refreshToken);
},
});
};
void init();
return () => destroyCheckout();
}, []);
| Level | Issue | Solution |
|---|---|---|
| CRITICAL | Using publicStorefront() for cart, auth, customer, order, or payment flows | Use the session accessor (serverStorefront() on server, clientStorefront() on client) |
| CRITICAL | Using clientStorefront() on the server | Use the server accessor — clientStorefront() throws on the server |
| CRITICAL | Using deprecated @commercengine/storefront-sdk-nextjs | Migrate to @commercengine/storefront/nextjs with createNextjsStorefront() |
| HIGH | Missing bootstrap component in root layout | Mount a client component calling storefront.bootstrap() once in the root layout |
| HIGH | Bootstrapping anonymous auth in SSG/pre-render code | Use publicStorefront() instead — pre-render code must not create sessions |
| MEDIUM | Fetching session-aware data in the root layout | Move it into a request-aware boundary and use the server accessor |
setup/ - Basic SDK installation and framework detectionssr/ - Custom SSR bindings with @commercengine/ssr-utils (Nuxt and other unsupported frameworks)auth/ - Authentication flowscart-checkout/ - Cart and Hosted Checkout patterns