From harness-claude
Prefetches TanStack Query data on the server and hydrates the client cache using dehydrate/hydrate and HydrationBoundary, eliminating loading spinners in Next.js App Router.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:tanstack-prefetchingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Hydrate the client cache from server-fetched data using dehydrate/hydrate and HydrationBoundary
Hydrate the client cache from server-fetched data using dehydrate/hydrate and HydrationBoundary
QueryClient in the Server Component and prefetch data with queryClient.prefetchQuery().<HydrationBoundary> component — it hydrates the client-side QueryClient automatically.dehydrate(queryClient) from @tanstack/react-query to serialize the cache for transport to the client.useQuery() with the same key used during prefetch — the data is available immediately with no loading state.queryClient.prefetchQuery() (not ensureQueryData) when you do not need the return value — it avoids an extra await.queryClient.prefetchQuery() in a onMouseEnter handler to warm the cache before navigation.staleTime to match your revalidation window — data prefetched at render time should not immediately re-fetch on mount.// app/posts/page.tsx — Server Component with prefetch
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query';
import { postListOptions } from '@/queries/posts';
import { PostList } from './post-list';
export default async function PostsPage() {
const queryClient = new QueryClient();
// Prefetch on the server — data is fetched once, not per-component
await queryClient.prefetchQuery(postListOptions({}));
return (
// Injects dehydrated cache into the page
<HydrationBoundary state={dehydrate(queryClient)}>
<PostList />
</HydrationBoundary>
);
}
// app/posts/post-list.tsx — Client Component, no loading state
'use client';
import { useQuery } from '@tanstack/react-query';
import { postListOptions } from '@/queries/posts';
export function PostList() {
// Data is immediately available — cache was hydrated from server
const { data: posts } = useQuery(postListOptions({}));
return <ul>{posts?.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}
// Prefetch on hover — warm cache before navigation
function PostLink({ id }: { id: string }) {
const queryClient = useQueryClient();
return (
<Link
href={`/posts/${id}`}
onMouseEnter={() => queryClient.prefetchQuery(postDetailOptions(id))}
>
View Post
</Link>
);
}
TanStack Query's SSR pattern solves the classic problem: server-rendered HTML contains data, but the client-side React Query cache is empty on mount, causing a flash of loading state as queries re-execute.
Dehydration/hydration mechanism: dehydrate(queryClient) serializes successful query results into a plain JSON-serializable object. <HydrationBoundary state={dehydratedState}> deserializes it into the client's QueryClient on mount. The client queries then find their data already in cache and skip the initial fetch.
staleTime is critical for SSR: Without staleTime, TanStack Query considers all queries stale immediately on mount and triggers background refetches — wasting the server prefetch. Set staleTime to at least as long as the server render takes (e.g., Infinity for fully static data, or a few minutes for semi-fresh data).
New QueryClient per request: In Server Components, create a new QueryClient() per page render, not a shared singleton. A singleton would leak data between user requests in a server-side Node.js process.
Multiple prefetches: Prefetch all queries needed by a page segment at once using Promise.all:
await Promise.all([
queryClient.prefetchQuery(postListOptions({})),
queryClient.prefetchQuery(categoriesOptions()),
]);
Router-level prefetch: For non-Next.js apps, TanStack Router has built-in prefetch integration via loader functions that call ensureQueryData. This achieves the same effect without manual dehydrate/hydrate wiring.
https://tanstack.com/query/latest/docs/framework/react/guides/prefetching
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeTanStack Query v5 integration with Next.js 16. Server-side prefetching, hydration, useQuery, useMutation, cache management.
Provides TanStack Query v5 reference for React data fetching, caching, server state management using useQuery/useMutation hooks, QueryClient setup, optimistic updates, Next.js SSR/hydration, testing, TypeScript, and advanced patterns.
Provides expertise in TanStack Query for React/Next.js data fetching, caching (staleTime/gcTime), mutations, optimistic updates, cache invalidation, and App Router SSR hydration.