# Tanstack Query

> TanStack Query v5 server state management for React. Covers query/mutation patterns, v4-to-v5 migration (object syntax, gcTime, isPending, keepPreviousData), optimistic updates via useMutationState, SSR/hydration with HydrationBoundary, infinite queries, offline/PWA support, error boundaries with throwOnError, and React 19 Suspense integration. Use when building data fetching, fixing migration errors, debugging hydration mismatches, implementing caching strategies, or configuring mutations.

- Skill: `oakoss/tanstack-query` (Agent Skill, multi-file: 16 files)
- Install (CLI): `npx skillmds add oakoss/tanstack-query`
- Raw SKILL.md: https://api.skillmd.com/api/skills/oakoss/tanstack-query/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: oakoss (https://skillmd.com/u/oakoss)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/oakoss/tanstack-query

---


# TanStack Query

## Overview

TanStack Query is an **async state manager**, not a data fetching library. You provide a `queryFn` that returns a Promise; React Query handles caching, deduplication, background updates, and stale data management.

**When to use:** Infinite scrolling, offline-first apps, auto-refetching on focus/reconnect, complex cache invalidation, React Native, hybrid server/client apps.

**When NOT to use:** Purely synchronous state (useState/Zustand), normalized GraphQL caching (Apollo/urql), server-components-only apps (native fetch), simple fetch-and-display (server components).

## Quick Reference

| Pattern           | API                                               | Key Points                             |
| ----------------- | ------------------------------------------------- | -------------------------------------- |
| Basic query       | `useQuery({ queryKey, queryFn })`                 | Include params in queryKey             |
| Suspense query    | `useSuspenseQuery(options)`                       | No `enabled` option allowed            |
| Parallel queries  | `useQueries({ queries, combine })`                | Dynamic parallel fetching              |
| Dependent query   | `useQuery({ enabled: !!dep })`                    | Wait for prerequisite data             |
| Query options     | `queryOptions({ queryKey, queryFn })`             | Reusable, type-safe config             |
| Basic mutation    | `useMutation({ mutationFn, onSuccess })`          | Invalidate on success                  |
| Mutation state    | `useMutationState({ filters, select })`           | Cross-component mutation tracking      |
| Optimistic update | `onMutate` -> cancel -> snapshot -> set           | Rollback in `onError`                  |
| Infinite query    | `useInfiniteQuery({ initialPageParam })`          | `initialPageParam` required in v5      |
| Prefetch          | `queryClient.prefetchQuery(options)`              | Preload on hover/intent                |
| Invalidation      | `queryClient.invalidateQueries({ queryKey })`     | Fuzzy-matches by default, active only  |
| Cancellation      | `queryFn: ({ signal }) => fetch(url, { signal })` | Auto-cancel on key change              |
| Select transform  | `select: (data) => data.filter(...)`              | Structural sharing preserved           |
| Skip token        | `queryFn: id ? () => fetch(id) : skipToken`       | Type-safe conditional disabling        |
| Serial mutations  | `useMutation({ scope: { id } })`                  | Same scope ID runs mutations in serial |

## v5 Migration Quick Reference

| v4 (Removed)                   | v5 (Use Instead)                           |
| ------------------------------ | ------------------------------------------ |
| `useQuery(key, fn, opts)`      | `useQuery({ queryKey, queryFn, ...opts })` |
| `cacheTime`                    | `gcTime`                                   |
| `isLoading` (no data)          | `isPending`                                |
| `keepPreviousData: true`       | `placeholderData: keepPreviousData`        |
| `onSuccess/onError` on queries | `useEffect` or mutation callbacks          |
| `useErrorBoundary`             | `throwOnError`                             |
| No `initialPageParam`          | `initialPageParam` required                |
| Error type `unknown`           | Error type defaults to `Error`             |

## Common Mistakes

| Mistake                                    | Correct Pattern                                           |
| ------------------------------------------ | --------------------------------------------------------- |
| Checking `isPending` before `data`         | Data-first: check `data` -> `error` -> `isPending`        |
| Copying server state to local useState     | Use data directly or derived state pattern                |
| Creating QueryClient in component          | Create once outside component or in useState              |
| Using `refetch()` for parameter changes    | Include params in queryKey, let it refetch automatically  |
| Same key for useQuery and useInfiniteQuery | Use distinct key segments (different cache structures)    |
| Inline select without memoization          | Extract to stable function or useCallback                 |
| Using `catch` without re-throwing          | Throw errors in queryFn (fetch doesn't reject on 4xx/5xx) |
| Manual generics on useQuery                | Type the queryFn return, let inference work               |
| Destructuring query for type narrowing     | Keep query object intact for proper narrowing             |
| Using `enabled` with `useSuspenseQuery`    | Use conditional rendering to mount/unmount component      |
| Not awaiting prefetch for SSR              | Await `prefetchQuery` to avoid hydration mismatches       |
| `invalidateQueries` not refetching all     | Use `refetchType: 'all'` for inactive queries             |

## Delegation

- **Query pattern discovery**: Use `Explore` agent
- **Cache strategy review**: Use `Task` agent
- **Code review**: Delegate to `code-reviewer` agent

> If the `tanstack-router` skill is available, delegate route loader and preloading patterns to it.
> If the `tanstack-form` skill is available, delegate form submission and mutation coordination to it.
> If the `tanstack-table` skill is available, delegate server-side table patterns to it.
> If the `tanstack-start` skill is available, delegate server functions and SSR data loading to it.
> If the `tanstack-devtools` skill is available, delegate query cache debugging and inspection to it.
> If the `tanstack-db` skill is available, delegate reactive client-side database and live query patterns to it.
> If the `tanstack-virtual` skill is available, delegate list virtualization and infinite scroll rendering to it.
> If the `tanstack-store` skill is available, delegate shared client-side reactive state management to it.
> If the `electricsql` skill is available, delegate ElectricSQL real-time Postgres sync patterns to it.
> If the `local-first` skill is available, delegate local-first architecture decisions and sync engine selection to it.

## References

- [Basic patterns, architecture, and query variants](references/basic-patterns.md)
- [Query keys and factory patterns](references/query-keys.md)
- [Mutations, optimistic updates, and MutationCache](references/mutations.md)
- [Cache operations, staleTime vs gcTime, seeding](references/caching.md)
- [Data transformations and select patterns](references/data-transformations.md)
- [Performance optimization with render tracking and structural sharing](references/performance.md)
- [Error handling strategies](references/error-handling.md)
- [Infinite queries and pagination](references/infinite-queries.md)
- [Offline mode and persistence](references/offline-mode.md)
- [WebSocket and real-time integration](references/websocket-integration.md)
- [SSR and hydration patterns](references/ssr-hydration.md)
- [TypeScript patterns](references/typescript-patterns.md)
- [Testing with MSW and React Testing Library](references/testing.md)
- [Known v5 issues and workarounds](references/known-issues.md)
- [Caching coordination with Router](references/caching-coordination.md) — single-source caching strategy, disabling Router cache, coordinated configuration

