SuperAPI AI Directory

tanstack-query-intent-lifecycle-ssr-hydration-and-streaming

Frontend & websites

View repository

Updated 10-16 08:19

About this skill

Setup

import {
  HydrationBoundary,
  QueryClient,
  dehydrate,
} from '@tanstack/react-query'

export async function PostsPage() { const queryClient = new QueryClient() await queryClient.prefetchQuery({ queryKey: ['posts'], queryFn: async () => [{ id: 1 }], }) return ( ) }

function Posts() { return Hydrated posts render here }


## Core Patterns

### Put TanStack Start and Router first

```ts
import { QueryClient } from '@tanstack/react-query'
import { createRouter } from '@tanstack/react-router'
import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'
import { routeTree } from './routeTree.gen'

const queryClient = new QueryClient()
const router = createRouter({ routeTree, context: { queryClient } })

setupRouterSsrQueryIntegration({ router, queryClient })

Use per-request clients

import { QueryClient } from '@tanstack/react-query'

export function createSsrQueryClient() {
  return new QueryClient({
    defaultOptions: { queries: { staleTime: 60_000 } },
  })
}

Hydrate only prefetched data

import {
  HydrationBoundary,
  QueryClient,
  dehydrate,
} from '@tanstack/react-query'

export async function Page() {
  const queryClient = new QueryClient()
  await queryClient.prefetchQuery({
    queryKey: ['profile'],
    queryFn: async () => ({ name: 'Tanner' }),
  })
  return (
    <HydrationBoundary state={dehydrate(queryClient)}>
      <main>Profile</main>
    </HydrationBoundary>
  )
}

Common Mistakes

CRITICAL RSC renders fetched data twice

Wrong:

import {
  HydrationBoundary,
  QueryClient,
  dehydrate,
} from '@tanstack/react-query'

export async function Page() {
  const queryClient = new QueryClient()
  const posts = await queryClient.fetchQuery({
    queryKey: ['posts'],
    queryFn: async () => [{ id: 1 }],
  })
  return (
    <>
      <p>{posts.length}</p>
      <HydrationBoundary state={dehydrate(queryClient)}>
        <main>Posts</main>
      </HydrationBoundary>
    </>
  )
}

Correct:

import {
  HydrationBoundary,
  QueryClient,
  dehydrate,
} from '@tanstack/react-query'

export async function Page() {
  const queryClient = new QueryClient()
  await queryClient.prefetchQuery({
    queryKey: ['posts'],
    queryFn: async () => [{ id: 1 }],
  })
  return (
    <HydrationBoundary state={dehydrate(queryClient)}>
      <main>Posts</main>
    </HydrationBoundary>
  )
}

Server-rendered derived data can desynchronize from client-refetched Query data.

Source: TanStack/query:docs/framework/react/guides/advanced-ssr.md

CRITICAL Suspense query not prefetched on server

Wrong:

import { useSuspenseQuery } from '@tanstack/react-query'

export function Posts() {
  const { data } = useSuspenseQuery({
    queryKey: ['posts'],
    queryFn: async () => [{ id: 1 }],
  })
  return <pre>{JSON.stringify(data)}</pre>
}

Correct:

import {
  HydrationBoundary,
  QueryClient,
  dehydrate,
} from '@tanstack/react-query'

export async function Page() {
  const queryClient = new QueryClient()
  await queryClient.prefetchQuery({
    queryKey: ['posts'],
    queryFn: async () => [{ id: 1 }],
  })
  return (
    <HydrationBoundary state={dehydrate(queryClient)}>
      <main>Posts</main>
    </HydrationBoundary>
  )
}

A suspense query that is not prefetched can fetch on the server, fail to hydrate, then fetch again on the client.

Source: TanStack/query:docs/framework/react/guides/ssr.md

HIGH SvelteKit query runs after SSR response

Wrong:

import { QueryClient } from '@tanstack/svelte-query'

export const queryClient = new QueryClient()

Correct:

import { browser } from '$app/environment'
import { QueryClient } from '@tanstack/svelte-query'

export const queryClient = new QueryClient({
  defaultOptions: { queries: { enabled: browser } },
})

SvelteKit SSR needs browser-gated default query execution unless server data is explicitly prefetched.

Source: TanStack/query:docs/framework/svelte/ssr.md

See also: compositions/compose-query-with-tanstack-router-and-start for TanStack-owned SSR routing.