accelint-tanstack-query-best-practices
Use when configuring QueryClient, implementing mutations, debugging performance, or adding optimistic updates with @tanstack/react-query in Next.js App Router. Covers factory patterns, query keys, cache invalidation, observer debugging, HydrationBoundary, multi-layer caching. Keywords TanStack Query, useSuspenseQuery, useQuery, useMutation, invalidateQueries, staleTime, gcTime, refetch, hydration.
What this skill does
# 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.
## Before Using TanStack Query, Ask
### State Classification
- **Is this server state or client state?** TanStack Query manages server state (API data, database records, external system state). UI state (modals, themes, form drafts) belongs in Zustand or useState.
- **Does this data change after initial render?** Static reference data might not need TanStack Query's refetching machinery. Consider if simpler alternatives suffice.
### Cache Strategy
- **How fresh does this data need to be?** Lookup tables can have 1-hour staleTime. Real-time tracking needs 5-second staleTime with refetchInterval. Match configuration to business requirements.
- **What's the query lifecycle?** Frequently-accessed data needs higher gcTime. One-time detail views can have aggressive garbage collection.
### Observer Economics
- **How many components will subscribe to this query?** >10 observers on a single cache entry suggests hoisting queries to parent. >100 observers indicates architectural issues.
- **Am I creating N queries or 1 query with N observers?** List items should receive props from parent query, not call individual useQuery hooks.
## How to Use
This skill uses **progressive disclosure** to minimize context usage. Load references based on your scenario:
### Scenario 1: Setting Up Query Client
**MANDATORY - READ ENTIRE FILE**: Read [`query-client-setup.md`](references/query-client-setup.md) (~125 lines) and [`server-integration.md`](references/server-integration.md) (~151 lines) completely for server/client setup patterns.
**Do NOT Load** other references for initial setup.
Copy [assets/query-client.ts](assets/query-client.ts) for production-ready configuration.
### Scenario 2: Building Query Hooks
1. **MANDATORY**: Read [`query-keys.md`](references/query-keys.md) (~151 lines) for key factory setup
2. If using server components: Read [`server-integration.md`](references/server-integration.md)
3. **Do NOT Load** mutations-and-updates.md unless implementing mutations
Use decision tables below for configuration values.
### Scenario 3: Implementing Mutations
**MANDATORY - READ ENTIRE FILE**: Read [`mutations-and-updates.md`](references/mutations-and-updates.md) (~345 lines) completely. Reference [`patterns-and-pitfalls.md`](references/patterns-and-pitfalls.md) for rollback patterns.
**Do NOT Load** caching-strategy.md for basic CRUD mutations.
### Scenario 4: Debugging Performance Issues
1. First, check Observer Count Thresholds table below (lines 121-129)
2. If observer count >50: Read [`patterns-and-pitfalls.md`](references/patterns-and-pitfalls.md)
3. If large dataset issues: Read [`fundamentals.md`](references/fundamentals.md) for structural sharing
4. **Do NOT Load** all references - diagnose first, then load targeted content
### Scenario 5: Multi-Layer Caching Strategy
**MANDATORY**: Read [`caching-strategy.md`](references/caching-strategy.md) (~198 lines) for unified Next.js use cache + TanStack Query + HTTP cache patterns.
**Do NOT Load** if only using client-side TanStack Query.
## Query Configuration Decision Matrix
| Data Type | staleTime | gcTime | refetchInterval | structuralSharing | Notes |
|-----------|-----------|--------|-----------------|-------------------|-------|
| **Reference/Lookup** | 1hr | Infinity | - | true | Countries, categories, static enums |
| **User Profile** | 5min | 10min | - | true | Changes infrequently, moderate freshness |
| **Real-time Tracking** | 5s | 30s | 5s | false | High update frequency, large payloads |
| **Live Dashboard** | 2s | 1min | 2s | Depends on size | Balance freshness vs performance |
| **Detail View** | 30s | 2min | - | true | Fetched on-demand, moderate caching |
| **Search Results** | 1min | 5min | - | true | Cacheable, not time-sensitive |
## Mutation Pattern Selection
| Scenario | Pattern | When to Use |
|----------|---------|-------------|
| **Form submission** | Pessimistic | Multi-step forms, server validation required, error messages needed before proceeding |
| **Toggle/checkbox** | Optimistic | Binary state changes, low latency required, easy to rollback |
| **Drag and drop** | Optimistic | Immediate visual feedback essential, reordering operations, non-critical data |
| **Batch operations** | Pessimistic | Multiple items, partial failures possible, user needs confirmation of what succeeded |
| **Life-critical ops** | Pessimistic | Medical, financial, safety-critical systems where UI must match server reality |
| **Audit trail required** | Pessimistic | Compliance systems where operator actions must match logged events exactly |
## Query Key Architecture
Use hierarchical factories for consistent invalidation:
```typescript
// Recommended structure
export const keys = {
all: () => ['domain'] as const,
lists: () => [...keys.all(), 'list']Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.