📡 Skill: tanstack-query-expert (v1.0.0)
Executive Summary
Senior Server State Architect for TanStack Query v5 (2026). Specialized in reactive data fetching, advanced caching, and high-performance integration with React 19 and Next.js 16. Expert in eliminating waterfalls, managing complex mutation states, and leveraging platform-level caching via Next.js "use cache" and Partial Prerendering (PPR).
📋 The Conductor's Protocol
- Architecture Choice: Determine if data fetching should happen in RSC (via React 19
use hook + "use cache") or on the client (via TanStack Query).
- Hydration Strategy: For SSR/PPR, always prefetch on the server and use
HydrationBoundary to ensure instant client-side data availability.
- Mutation Tracking: Use
useMutationState to handle global loading/pending states without prop drilling.
- Verification: Use TanStack Query Devtools v5 to audit query states, stale times, and cache invalidation.
🛠️ Mandatory Protocols (2026 Standards)
1. The "Object Syntax" Rule
TanStack Query v5 ONLY supports the object-based syntax for all hooks.
- Rule: Never use the deprecated positional argument syntax (e.g.,
useQuery(key, fn)).
- Correct:
useQuery({ queryKey: [...], queryFn: ... }).
2. React 19 & Next.js 16 Integration
- PPR First: Wrap client components using TanStack Query in
<Suspense> to allow Next.js 16 to stream content while serving the static shell.
- "use cache" Directive: For server-side prefetching, utilize Next.js 16's
"use cache" to cache the prefetch results at the platform level.
- Action Mutations: Prefer React 19 Actions for simple form mutations; use TanStack Query mutations for complex state, optimistic updates, and background refetching.
3. Cache & Performance Hardening
- Stale Time: Default to at least
5000 (5s) to prevent excessive refetching.
- GC Time: Use
gcTime (renamed from cacheTime in v5) to manage memory cleanup.
- Query Keys: Always use stable, array-based query keys. Treat keys as unique identifiers for your data.
🚀 Show, Don't Just Tell (Implementation Patterns)
Quick Start: Modern Query with Suspense (React 19)
"use client";
import { useSuspenseQuery } from "@tanstack/react-query";
import { queryOptions } from "@tanstack/react-query";
// Pattern: Reusable Query Options
export const userOptions = (id: string) => queryOptions({
queryKey: ["users", id],
queryFn: async () => {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error("Failed to fetch");
return res.json();
},
staleTime: 1000 * 60 * 5, // 5 min
});
export function UserProfile({ id }: { id: string }) {
// Guaranteed data availability via Suspense
const { data: user } = useSuspenseQuery(userOptions(id));
return <div>Welcome, {user.name}</div>;
}
Advanced Pattern: Global Mutation Tracking
import { useMutationState } from "@tanstack/react-query";
function PendingUploads() {
const pendingVariables = useMutationState({
filters: { status: "pending", mutationKey: ["upload"] },
select: (mutation) => mutation.state.variables as { fileName: string },
});
return (
<ul>
{pendingVariables.map((vars, i) => (
<li key={i} className="opacity-50 italic text-blue-400">
Uploading {vars.fileName}...
</li>
))}
</ul>
);
}
🛡️ The Do Not List (Anti-Patterns)
- DO NOT use
onSuccess, onError, or onSettled in useQuery. They are removed in v5. Use useEffect or move logic to queryFn.
- DO NOT ignore
isPending. It replaced isLoading in v5 for "no data yet" states.
- DO NOT use
useQuery without a queryKey. It's the only way to manage the cache effectively.
- DO NOT forget to
await prefetchQuery on the server. Non-awaited prefetches lead to hydration mismatches.
- DO NOT use
enabled with useSuspenseQuery. It's incompatible with the guarantee of data presence.
📂 Progressive Disclosure (Deep Dives)
🛠️ Specialized Tools & Scripts
scripts/audit-query-keys.ts: Checks for non-array query keys or unstable key generation.
scripts/generate-query-hook.py: Boilerplate generator for v5 query/mutation pairs.
🎓 Learning Resources
Updated: January 23, 2026 - 16:45
1---2name: tanstack-query-expert3description: Senior Server State Architect for TanStack Query v5 (2026). Specialized in reactive data fetching, advanced caching, and high-performance integration with React 19 and Next.js 16. Expert in eliminating waterfalls, managing complex mutation states, and leveraging platform-level caching via Next.js `"use cache"` and Partial Prerendering (PPR).4---56# 📡 Skill: tanstack-query-expert (v1.0.0)78## Executive Summary9Senior Server State Architect for TanStack Query v5 (2026). Specialized in reactive data fetching, advanced caching, and high-performance integration with React 19 and Next.js 16. Expert in eliminating waterfalls, managing complex mutation states, and leveraging platform-level caching via Next.js `"use cache"` and Partial Prerendering (PPR).1011---1213## 📋 The Conductor's Protocol14151. **Architecture Choice**: Determine if data fetching should happen in RSC (via React 19 `use` hook + `"use cache"`) or on the client (via TanStack Query).162. **Hydration Strategy**: For SSR/PPR, always prefetch on the server and use `HydrationBoundary` to ensure instant client-side data availability.173. **Mutation Tracking**: Use `useMutationState` to handle global loading/pending states without prop drilling.184. **Verification**: Use TanStack Query Devtools v5 to audit query states, stale times, and cache invalidation.1920---2122## 🛠️ Mandatory Protocols (2026 Standards)2324### 1. The "Object Syntax" Rule25TanStack Query v5 ONLY supports the object-based syntax for all hooks.26- **Rule**: Never use the deprecated positional argument syntax (e.g., `useQuery(key, fn)`).27- **Correct**: `useQuery({ queryKey: [...], queryFn: ... })`.2829### 2. React 19 & Next.js 16 Integration30- **PPR First**: Wrap client components using TanStack Query in `<Suspense>` to allow Next.js 16 to stream content while serving the static shell.31- **"use cache" Directive**: For server-side prefetching, utilize Next.js 16's `"use cache"` to cache the prefetch results at the platform level.32- **Action Mutations**: Prefer React 19 Actions for simple form mutations; use TanStack Query mutations for complex state, optimistic updates, and background refetching.3334### 3. Cache & Performance Hardening35- **Stale Time**: Default to at least `5000` (5s) to prevent excessive refetching.36- **GC Time**: Use `gcTime` (renamed from `cacheTime` in v5) to manage memory cleanup.37- **Query Keys**: Always use stable, array-based query keys. Treat keys as unique identifiers for your data.3839---4041## 🚀 Show, Don't Just Tell (Implementation Patterns)4243### Quick Start: Modern Query with Suspense (React 19)44```tsx45"use client";4647import { useSuspenseQuery } from "@tanstack/react-query";48import { queryOptions } from "@tanstack/react-query";4950// Pattern: Reusable Query Options51export const userOptions = (id: string) => queryOptions({52 queryKey: ["users", id],53 queryFn: async () => {54 const res = await fetch(`/api/users/${id}`);55 if (!res.ok) throw new Error("Failed to fetch");56 return res.json();57 },58 staleTime: 1000 * 60 * 5, // 5 min59});6061export function UserProfile({ id }: { id: string }) {62 // Guaranteed data availability via Suspense63 const { data: user } = useSuspenseQuery(userOptions(id));6465 return <div>Welcome, {user.name}</div>;66}67```6869### Advanced Pattern: Global Mutation Tracking70```tsx71import { useMutationState } from "@tanstack/react-query";7273function PendingUploads() {74 const pendingVariables = useMutationState({75 filters: { status: "pending", mutationKey: ["upload"] },76 select: (mutation) => mutation.state.variables as { fileName: string },77 });7879 return (80 <ul>81 {pendingVariables.map((vars, i) => (82 <li key={i} className="opacity-50 italic text-blue-400">83 Uploading {vars.fileName}...84 </li>85 ))}86 </ul>87 );88}89```9091---9293## 🛡️ The Do Not List (Anti-Patterns)94951. **DO NOT** use `onSuccess`, `onError`, or `onSettled` in `useQuery`. They are removed in v5. Use `useEffect` or move logic to `queryFn`.962. **DO NOT** ignore `isPending`. It replaced `isLoading` in v5 for "no data yet" states.973. **DO NOT** use `useQuery` without a `queryKey`. It's the only way to manage the cache effectively.984. **DO NOT** forget to `await` prefetchQuery on the server. Non-awaited prefetches lead to hydration mismatches.995. **DO NOT** use `enabled` with `useSuspenseQuery`. It's incompatible with the guarantee of data presence.100101---102103## 📂 Progressive Disclosure (Deep Dives)104105- **[v5 Migration & Breaking Changes](./references/migration.md)**: Moving from v4 to v5 safely.106- **[Next.js 16 SSR & Hydration](./references/ssr-hydration.md)**: Prefetching, `HydrationBoundary`, and `"use cache"`.107- **[Advanced Mutations & Optimistic UI](./references/mutations.md)**: useMutationState and simplified v5 patterns.108- **[Performance & Infinite Queries](./references/performance-infinite.md)**: maxPages and bi-directional pagination.109110---111112## 🛠️ Specialized Tools & Scripts113114- `scripts/audit-query-keys.ts`: Checks for non-array query keys or unstable key generation.115- `scripts/generate-query-hook.py`: Boilerplate generator for v5 query/mutation pairs.116117---118119## 🎓 Learning Resources120- [TanStack Query Docs](https://tanstack.com/query/latest)121- [TkDodo's Blog (Maintainer)](https://tkdodo.eu/blog/)122- [React 19 Data Fetching Guide](https://react.dev/reference/react/use)123124---125*Updated: January 23, 2026 - 16:45*