diff --git a/docs/start/config.json b/docs/start/config.json
index cdf9f0b088d..28c7d5030ed 100644
--- a/docs/start/config.json
+++ b/docs/start/config.json
@@ -101,6 +101,10 @@
"label": "Server Routes",
"to": "framework/react/guide/server-routes"
},
+ {
+ "label": "Hydration Errors",
+ "to": "framework/react/guide/hydration-errors"
+ },
{
"label": "Selective SSR",
"to": "framework/react/guide/selective-ssr"
@@ -190,6 +194,10 @@
"label": "Server Routes",
"to": "framework/solid/guide/server-routes"
},
+ {
+ "label": "Hydration Errors",
+ "to": "framework/solid/guide/hydration-errors"
+ },
{
"label": "Selective SSR",
"to": "framework/solid/guide/selective-ssr"
diff --git a/docs/start/framework/react/guide/hydration-errors.md b/docs/start/framework/react/guide/hydration-errors.md
new file mode 100644
index 00000000000..54929b41ebd
--- /dev/null
+++ b/docs/start/framework/react/guide/hydration-errors.md
@@ -0,0 +1,122 @@
+---
+id: hydration-errors
+title: Hydration Errors
+---
+
+### Why it happens
+- **Mismatch**: Server HTML differs from client render during hydration
+- **Common causes**: `Intl` (locale/time zone), `Date.now()`, random IDs, responsive-only logic, feature flags, user prefs
+
+### Strategy 1 — Make server and client match
+- **Pick a deterministic locale/time zone on the server** and use the same on the client
+- **Source of truth**: cookie (preferred) or `Accept-Language` header
+- **Compute once on the server** and hydrate as initial state
+
+```tsx
+// src/start.ts
+import { createStart, createMiddleware } from '@tanstack/react-start'
+import { getRequestHeader, getCookie, setCookie } from '@tanstack/react-start/server'
+
+const localeTzMiddleware = createMiddleware().server(async ({ next }) => {
+ const header = getRequestHeader('accept-language')
+ const headerLocale = header?.split(',')[0] || 'en-US'
+ const cookieLocale = getCookie('locale')
+ const cookieTz = getCookie('tz') // set by client later (see Strategy 2)
+
+ const locale = cookieLocale || headerLocale
+ const timeZone = cookieTz || 'UTC' // deterministic until client sends tz
+
+ // Persist locale for subsequent requests (optional)
+ setCookie('locale', locale, { path: '/', maxAge: 60 * 60 * 24 * 365 })
+
+ return next({ context: { locale, timeZone } })
+})
+
+export const startInstance = createStart(() => ({
+ requestMiddleware: [localeTzMiddleware],
+}))
+```
+
+```tsx
+// src/routes/index.tsx (example)
+import * as React from 'react'
+import { createFileRoute } from '@tanstack/react-router'
+import { createServerFn } from '@tanstack/react-start'
+import { getCookie } from '@tanstack/react-start/server'
+
+export const getServerNow = createServerFn().handler(async () => {
+ const locale = getCookie('locale') || 'en-US'
+ const timeZone = getCookie('tz') || 'UTC'
+ return new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeStyle: 'short', timeZone }).format(new Date())
+})
+
+export const Route = createFileRoute('/')({
+ loader: () => getServerNow(),
+ component: () => {
+ const serverNow = Route.useLoaderData() as string
+ return
+ },
+})
+```
+
+### Strategy 2 — Let the client tell you its environment
+- On first visit, set a cookie with the client time zone; SSR uses `UTC` until then
+- Do this without risking mismatches
+
+```tsx
+import * as React from 'react'
+import { ClientOnly } from '@tanstack/react-router'
+
+function SetTimeZoneCookie() {
+ React.useEffect(() => {
+ const tz = Intl.DateTimeFormat().resolvedOptions().timeZone
+ document.cookie = `tz=${tz}; path=/; max-age=31536000`
+ }, [])
+ return null
+}
+
+export function AppBoot() {
+ return (
+
+
+
+ )
+}
+```
+
+### Strategy 3 — Make it client-only
+- Wrap unstable UI in `` to avoid SSR and mismatches
+
+```tsx
+import { ClientOnly } from '@tanstack/react-router'
+
+—}>
+
+
+```
+
+### Strategy 4 — Disable or limit SSR for the route
+- Use Selective SSR to avoid rendering the component on the server
+
+```tsx
+export const Route = createFileRoute('/unstable')({
+ ssr: 'data-only', // or false
+ component: () => ,
+})
+```
+
+### Strategy 5 — Last resort suppression
+- For small, known-different nodes, you can use React’s `suppressHydrationWarning`
+
+```tsx
+
+```
+
+### Checklist
+- **Deterministic inputs**: locale, time zone, feature flags
+- **Prefer cookies** for client context; fallback to `Accept-Language`
+- **Use ``** for inherently dynamic UI
+- **Use Selective SSR** when server HTML cannot be stable
+- **Avoid blind suppression**; use `suppressHydrationWarning` sparingly
+
+See also: [Execution Model](../execution-model.md), [Code Execution Patterns](../code-execution-patterns.md), [Selective SSR](../selective-ssr.md), [Server Functions](../server-functions.md)
diff --git a/docs/start/framework/solid/guide/hydration-errors.md b/docs/start/framework/solid/guide/hydration-errors.md
new file mode 100644
index 00000000000..9b2ddd8caa3
--- /dev/null
+++ b/docs/start/framework/solid/guide/hydration-errors.md
@@ -0,0 +1,114 @@
+---
+id: hydration-errors
+title: Hydration Errors
+---
+
+### Why it happens
+- **Mismatch**: Server HTML differs from client render during hydration
+- **Common causes**: `Intl` (locale/time zone), `Date.now()`, random IDs, responsive-only logic, feature flags, user prefs
+
+### Strategy 1 — Make server and client match
+- **Pick a deterministic locale/time zone on the server** and use the same on the client
+- **Source of truth**: cookie (preferred) or `Accept-Language` header
+- **Compute once on the server** and hydrate as initial state
+
+```tsx
+// src/start.ts
+import { createStart, createMiddleware } from '@tanstack/solid-start'
+import { getRequestHeader, getCookie, setCookie } from '@tanstack/solid-start/server'
+
+const localeTzMiddleware = createMiddleware().server(async ({ next }) => {
+ const header = getRequestHeader('accept-language')
+ const headerLocale = header?.split(',')[0] || 'en-US'
+ const cookieLocale = getCookie('locale')
+ const cookieTz = getCookie('tz') // set by client later (see Strategy 2)
+
+ const locale = cookieLocale || headerLocale
+ const timeZone = cookieTz || 'UTC'
+
+ setCookie('locale', locale, { path: '/', maxAge: 60 * 60 * 24 * 365 })
+
+ return next({ context: { locale, timeZone } })
+})
+
+export const startInstance = createStart(() => ({
+ requestMiddleware: [localeTzMiddleware],
+}))
+```
+
+```tsx
+// src/routes/index.tsx (example)
+import { createFileRoute } from '@tanstack/solid-router'
+import { createServerFn } from '@tanstack/solid-start'
+import { getCookie } from '@tanstack/solid-start/server'
+
+export const getServerNow = createServerFn().handler(async () => {
+ const locale = getCookie('locale') || 'en-US'
+ const timeZone = getCookie('tz') || 'UTC'
+ return new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeStyle: 'short', timeZone }).format(new Date())
+})
+
+export const Route = createFileRoute('/')({
+ loader: () => getServerNow(),
+ component: () => {
+ const serverNow = Route.useLoaderData() as string
+ return
+ },
+})
+```
+
+### Strategy 2 — Let the client tell you its environment
+- On first visit, set a cookie with the client time zone; SSR uses `UTC` until then
+
+```tsx
+import { ClientOnly } from '@tanstack/solid-router'
+
+function SetTimeZoneCookie() {
+ if (typeof window !== 'undefined') {
+ const tz = Intl.DateTimeFormat().resolvedOptions().timeZone
+ document.cookie = `tz=${tz}; path=/; max-age=31536000`
+ }
+ return null
+}
+
+
+
+
+```
+
+### Strategy 3 — Make it client-only
+- Use `` or Solid’s `` to avoid SSR/hydration
+
+```tsx
+import { ClientOnly } from '@tanstack/solid-router'
+import { NoHydration } from 'solid-js/web'
+
+—}>
+
+
+
+
+
+
+```
+
+### Strategy 4 — Disable or limit SSR for the route
+- Use Selective SSR to avoid rendering the component on the server
+
+```tsx
+export const Route = createFileRoute('/unstable')({
+ ssr: 'data-only', // or false
+ component: () => ,
+})
+```
+
+### Strategy 5 — Last resort suppression
+- Prefer the tools above; avoid mismatches instead of hiding them
+
+### Checklist
+- **Deterministic inputs**: locale, time zone, feature flags
+- **Prefer cookies** for client context; fallback to `Accept-Language`
+- **Use ``/``** for inherently dynamic UI
+- **Use Selective SSR** when server HTML cannot be stable
+
+See also: [Execution Model](../execution-model.md), [Code Execution Patterns](../code-execution-patterns.md), [Selective SSR](../selective-ssr.md), [Server Functions](../server-functions.md)