accelint-tanstack-query-best-practices

Installation
SKILL.md

TanStack Query Best Practices

Expert patterns for TanStack Query in modern React applications with Next.js App Router and Server Components.

NEVER Do With TanStack Query

  • NEVER use a singleton QueryClient on the server - Creates data leakage between users and race conditions. Each request must get its own isolated QueryClient instance to prevent cached data from one user appearing for another.
  • NEVER synchronize query data to useState - Background refetches, invalidations, and optimistic updates all modify the cache. Local state copies become stale immediately, causing "my save didn't work" bugs. Use query data directly or derive with useMemo.
  • NEVER put queries inside list item components - Creates N observers for N items, causing O(n) iteration on every cache update. 200 list items calling useQuery creates 200 network requests and 200 observers. Hoist queries to parent components.
  • NEVER use unstable query keys - Arrays with non-guaranteed order, temporal queries with Date.now(), or object keys without deterministic serialization create infinite cache entries. Keys must be stable and deterministic.
  • NEVER skip enabled guards for dependent queries - Firing queries with undefined parameters creates garbage cache entries like ['tracks', undefined] and wastes network requests before real data arrives.
  • NEVER ignore AbortController signals - Without query cancellation support, unmounted components leave in-flight requests running, wasting bandwidth and potentially updating stale cache entries.
  • NEVER use optimistic updates for high-stakes or external mutations - Life-critical operations, audit trail systems, and mutations triggered by external events need pessimistic updates to ensure UI matches server state.
  • NEVER assume structural sharing is free - For datasets >1000 items updating frequently, structural sharing's O(n) deep equality checks become CPU overhead. Disable with structuralSharing: false for large, frequently-changing data.
  • NEVER skip onSettled in optimistic updates - onSettled is your cleanup guarantee even if onError throws. Without it, UI can be left in corrupted state when error handler fails. Always pair onMutate with onSettled for resource cleanup and cache consistency.
  • NEVER assume cache invalidation is synchronous - invalidateQueries triggers background refetches which can race with optimistic updates. Use cancelQueries in onMutate to prevent background refetches from overwriting your optimistic changes before the mutation completes.
  • NEVER use setQueryData without structural comparison - Directly setting cache data bypasses structural sharing and breaks referential equality optimizations. Wrap in updater function to preserve references for unchanged portions: setQueryData(key, (old) => ({ ...old, changed: value })) instead of setQueryData(key, newValue).
  • NEVER forget to handle hydration mismatches - Server-rendered data may differ from client expectations (timestamps, user-specific data, randomized content). Use suppressHydrationWarning on containers or ensure deterministic server/client rendering with stable timestamps and consistent data sources.
Related skills

More from gohypergiant/agent-skills

Installs
154
GitHub Stars
13
First Seen
Feb 7, 2026