Skip to main content

Server-Side Rendering

TanStack Query supports server-side rendering (SSR) with proper hydration, enabling you to prefetch data on the server and seamlessly transition to the client.

Why SSR with React Query?

  • Faster initial page load - Data is fetched on the server and sent with HTML
  • Better SEO - Search engines can crawl pre-rendered content
  • Improved perceived performance - Users see content immediately
  • Automatic cache hydration - Server data seamlessly transfers to client
React Query is designed to work seamlessly with SSR frameworks like Next.js, Remix, and others.
The App Router (Next.js 13+) is the recommended approach for new applications.

Setup

1

Create a client component provider

app/providers.tsx
Always create the QueryClient inside the component using useState to ensure each request gets its own cache.
2

Add provider to root layout

app/layout.tsx
3

Prefetch in Server Components

app/posts/page.tsx
4

Use in Client Components

app/posts/posts-list.tsx

HydrationBoundary

The HydrationBoundary component enables you to hydrate query data from the server:
HydrationBoundary only hydrates queries that don’t already exist in the client cache, making it safe to use at multiple levels.

Next.js Pages Router

For the Pages Router (Next.js 12 and below), use getServerSideProps or getStaticProps.

getServerSideProps

Prefetch data on every request:
pages/posts.tsx
Then in _app.tsx:
pages/_app.tsx
In the Pages Router, use the Hydrate component (deprecated but still supported). In the App Router, use HydrationBoundary instead.

getStaticProps

Prefetch data at build time for static generation:
pages/posts/[id].tsx

Advanced Patterns

Streaming with Suspense

Use React Suspense for progressive rendering:
app/posts/page.tsx
app/posts/sidebar.tsx
Prefetch critical above-the-fold content on the server, and let less important content stream in using Suspense.

Error Handling

Handle errors during SSR:
app/posts/page.tsx

Initial Data from Props

Pass server data as initial data:
Using initialData doesn’t provide the same benefits as proper hydration. Prefer using dehydrate and HydrationBoundary for better cache management.

Server-Only Code

Ensure server-only code doesn’t leak to the client:
lib/queries.ts
app/posts/page.tsx
Install the server-only package:

Dehydration Options

Control which queries to include in dehydrated state:

Available Options

Performance Optimization

Prefetch Only What’s Needed

Stale While Revalidate

Parallel Prefetching

Remix Integration

Use React Query with Remix:
app/routes/posts.tsx

Debugging SSR

Check Hydration Mismatches

Log Dehydrated State

Common Pitfalls

1

Sharing QueryClient Between Requests

Wrong:
Correct:
2

Query Key Mismatch

Ensure query keys match between server and client:
3

Not Using HydrationBoundary

Always wrap client components with HydrationBoundary:

Next Steps

TypeScript

Add type safety to SSR queries

DevTools

Debug hydration with React Query DevTools