# Ce Ssr Patterns

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

- Skill: `commercengine/ce-ssr-patterns` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add commercengine/ce-ssr-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/commercengine/ce-ssr-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: commercengine (https://skillmd.com/u/commercengine)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/commercengine/ce-ssr-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.

# SSR / Meta-Framework Patterns

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

## Impact Levels

- **CRITICAL** - Session continuity bugs, auth bugs
- **HIGH** - Common mistakes
- **MEDIUM** - Performance or maintainability issues

## References

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

## Shared Mental Model

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

### Bootstrap

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.

### Pre-rendering for SEO & Initial Load

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:

```typescript
// 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.

### Client-Side Fetching After Hydration

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:

```typescript
// 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 Quick Reference

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

## Hosted Checkout + SSR

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:

```typescript
// 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 `onTokensUpdated` receives two separate arguments `(accessToken, refreshToken)`. Checkout's `onTokensUpdated` receives a single object `({ accessToken, refreshToken })`. Do not mix these up.

```tsx
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();
}, []);
```

## Common Pitfalls (All SSR Frameworks)

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

## See Also

- `setup/` - Basic SDK installation and framework detection
- `ssr/` - Custom SSR bindings with `@commercengine/ssr-utils` (Nuxt and other unsupported frameworks)
- `auth/` - Authentication flows
- `cart-checkout/` - Cart and Hosted Checkout patterns

## Documentation

- **SDK Documentation**: https://www.commercengine.io/docs/sdk
- **LLM Reference**: https://llm-docs.commercengine.io/sdk/

