---
schema_version: "1"
id: e6c7f8c01e599ba50fdfe3d25e99341ddebf16147b251dcdb93babd1baca95a2
title: Server-Side Rendering (SSR) Differences with PWA Kit
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/commerce-cloud/sfnext/guides/sfnext-pwa-rendering.md
canonical_url: https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/sfnext-pwa-rendering.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: 520a5834b4c4dad29a1e80e17ab507ed77498819236113b3b826d98dd78d4288
products:
  - Composable Storefront
  - Salesforce APIs
---
# Server-Side Rendering (SSR) Differences with PWA Kit

PWA Kit and Storefront Next implement SSR, but with fundamentally different architectures that reflect their respective technology stacks. PWA Kit's SSR approach gives developers explicit control through Express and React Query, with optional partial hydration via Islands. Storefront Next uses React Router 7's built-in SSR with automatic streaming, middleware chains, and loader-based data fetching. Storefront Next's approach reduces boilerplate and provides better streaming performance, while the PWA Kit approach offers more granular control over hydration timing.

## Key Differences

| Aspect            | PWA Kit                              | Storefront Next                       |
| ----------------- | ------------------------------------ | ------------------------------------- |
| SSR Runtime       | Express server with `runtime.render` | React Router 7 framework mode         |
| Data Hydration    | React Query cache serialization      | Promise streaming with `use()` hook   |
| Middleware        | Express middleware                   | React Router middleware chain         |
| Partial Hydration | `Island` component with strategies   | Suspense boundaries with `createPage` |
| Server Context    | `useServerContext()` hook            | Context from middleware chain         |
| Code Splitting    | `@loadable/component`                | React Router's automatic splitting    |
| Cache Control     | Manual via `res.set()`               | Via HTTP response from middleware     |

## Data Flow Comparison

PWA Kit:

1. Express receives request.
2. React tree renders.
3. React Query hooks execute during render.
4. Data fetched, components re-render with data.
5. Query cache serialized to HTML.
6. Client hydrates with cached data.

Storefront Next:

1. React Router receives request.
2. Middleware chain runs (auth, config, i18n).
3. Loaders execute, return promises.
4. React renders, `use()` unwraps promises.
5. HTML streams as promises resolve.
6. Client hydrates, clientLoader runs.

## Hydration Approaches

**PWA Kit** offers fine-grained control with `Island`:

```javascript
<Island hydrateOn="visible">
  <Footer />
</Island>
```

**Storefront Next** uses Suspense boundaries:

```typescript
export default createPage({
  component: ProductDetail,
  fallback: <ProductSkeleton />,
});
```

## Storefront Conversion Considerations

1. useServerContext vs. Middleware: Server-side logic like setting cache headers moves from component hooks to middleware or loaders.

2. React Query vs. Loaders: Data fetching moves from hooks inside components to loader functions exported from route files.

3. Island vs. Suspense: Partial hydration with Island becomes Suspense boundaries with `createPage`.

4. Express routes vs. Resource routes: Custom API endpoints move from Express handlers to React Router resource routes.
