---
title: "Server rendering"
description: "Resolve request locale and hydrate React with the same verified catalog state."
canonical_url: "https://docs.linguana.dev/docs/build-with-code/server-rendering"
markdown_url: "https://docs.linguana.dev/docs/build-with-code/server-rendering.md"
x_farming_labs_generated_preamble: true
agent:
  task: "Resolve one request locale and create matching server/client hydration state."
  outcome: "SSR and hydration use the same locale and verified catalogs."
  prerequisites:
    - "The host can provide a Request and supported locale list."
    - "A deterministic embedded source catalog is available."
  files:
    - "The framework server locale bootstrap."
  verification:
    - "Conflicting override, preference, cookie, and header values follow documented precedence."
  rollback:
    - "Return the default locale with only the embedded source catalog."
  failureModes:
    - symptom: "React reports a hydration mismatch."
      resolution: "Serialize and reuse the exact server LocaleHydrationState."
---

# Server rendering
URL: /docs/build-with-code/server-rendering
LLM index: /llms.txt
Description: Resolve request locale and hydrate React with the same verified catalog state.
Related: /docs/reference/ssr, /docs/automate/test-integration

<!-- farming-labs:agent-contract:start -->
## Agent Contract

Task: Resolve one request locale and create matching server/client hydration state.
Outcome: SSR and hydration use the same locale and verified catalogs.

### Prerequisites

- The host can provide a Request and supported locale list.
- A deterministic embedded source catalog is available.

### Files

- `The framework server locale bootstrap.`

### Verification

- Conflicting override, preference, cookie, and header values follow documented precedence.

### Rollback

- Return the default locale with only the embedded source catalog.

### Failure Modes

- React reports a hydration mismatch. — Recovery: Serialize and reuse the exact server LocaleHydrationState.
<!-- farming-labs:agent-contract:end -->

# Configure server rendering

Import server helpers from `@linguanahq/react/ssr`. Resolve once per request, load only a verified catalog, and pass the resulting hydration state unchanged to the browser.

## Locale precedence

| Priority | Source | Typical owner |
| --- | --- | --- |
| 1 | Explicit `override` | Application route policy |
| 2 | `userPreference` | Signed-in account |
| 3 | `linguana_locale` cookie | Prior language selection |
| 4 | Weighted `Accept-Language` | Browser |
| 5 | `defaultLocale` | Project/application |

Exact locale matches win before language-only matches, so `fr-CA` may match configured `fr`.

```ts title="server/locale.ts"
import { resolveRequestLocale } from "@linguanahq/react/ssr";

const locale = resolveRequestLocale({
  request,
  override: routeLocale,
  userPreference: account?.locale,
  supportedLocales: ["en", "fr", "am"],
  defaultLocale: "en",
});
```

## Load and serialize

Attempt target catalog loading on the server. If it fails, return source locale and the embedded catalog instead of claiming the unavailable target.

```ts
const requested = resolveRequestLocale({
  request,
  supportedLocales: ["en", "fr"],
  defaultLocale: "en",
});

const target = requested === "en"
  ? undefined
  : await loadCatalog({
      endpoint: process.env.LINGUANA_API_URL!,
      projectId,
      environment,
      locale: requested,
      publishableKey: process.env.LINGUANA_PUBLISHABLE_KEY!,
    }).catch(() => undefined);

const hydrationState = createRequestHydrationState(
  target ? requested : "en",
  target ? [embeddedEnglish, target] : [embeddedEnglish],
);
```

Pass `hydrationState` to `LocaleProvider`. It contains schema version `1`, the resolved locale, and validated catalogs.

## Cookie and route ownership

The default cookie is first-party, path-wide, and `SameSite=Lax`. Linguana does not redirect or add locale path segments. If the application owns localized routes, pass that locale as `override` and keep URL generation in the router.

<Verification>
Create requests where override, account preference, cookie, and `Accept-Language` disagree. Assert the first supported value wins, then hydrate without a text mismatch.
</Verification>

<FailureGuide symptom="React reports a hydration mismatch" cause="The browser provider started with a locale or catalog set different from the server response." check="Inspect the serialized LocaleHydrationState and do not resolve the initial locale twice." />

## Next

Use the [SSR API reference](/docs/reference/ssr) and add the precedence cases to [integration testing](/docs/automate/test-integration).

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
Docs-scoped sitemap: [/docs/sitemap.md](/docs/sitemap.md).
Well-known sitemap: [/.well-known/sitemap.md](/.well-known/sitemap.md).
