In Next.js SSR/app-router, do not use useSuspenseQuery unless your server prefetch + hydration setup guarantees the data is already in the cache such that the component will not suspend.
Why: with standard hydration, if the query isn’t actually present on the client yet, useSuspenseQuery may suspend and you’ll get undesirable loading/empty HTML or server/client state mismatch. If you can’t guarantee “no suspend,” prefer useQuery (so the component renders with isLoading/pending state instead of relying on Suspense streaming).
Apply this rule:
useSuspenseQuery can be appropriate because pending promises can be hydrated and consumed.HydrationBoundary + awaited prefetch), use useQuery in the client component to avoid Suspense-related mismatches.Also keep SSR hydration details correct:
hydrate.transformPromise.prefetchQuery({ queryFn }) uses a function queryFn: () => getPosts().then(serialize).Example (safe default for app-router with awaited prefetch):
// app/posts/page.tsx (Server)
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'
import Posts from './posts'
import { getPosts } from './api'
export default async function PostsPage() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: getPosts,
})
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<Posts />
</HydrationBoundary>
)
}
// app/posts/posts.tsx (Client)
'use client'
import { useQuery } from '@tanstack/react-query'
import { getPosts } from './api'
export default function Posts() {
const { data } = useQuery({ queryKey: ['posts'], queryFn: getPosts })
return <div>{data?.length}</div>
}