React Query Best Practices
Important: This guide targets React Query v4. Some patterns may differ in v5.
Comprehensive guide for React Query v4 (TanStack Query) based on TkDodo's authoritative blog series. Contains 24 rules across 7 categories, prioritized by impact.
When to Apply
Reference these guidelines when:
-
Implementing new queries or mutations
-
Integrating WebSockets with React Query
-
Setting up query invalidation patterns
-
Debugging React Query behavior
-
Optimizing render performance
-
TypeScript integration questions
Rule Categories by Priority
Priority Category Impact Prefix
1 Query Keys & Patterns CRITICAL query-
2 Mutations & Updates CRITICAL mutation-
3 Caching Strategy HIGH cache-
4 WebSocket Integration HIGH websocket-
5 TypeScript Integration MEDIUM typescript-
6 Testing Patterns MEDIUM testing-
7 Common Pitfalls MEDIUM troubleshoot-
8 Migration to v5 HIGH migration-
Quick Reference
- Query Keys & Patterns (CRITICAL)
-
query-keys-as-dependencies
-
Include all queryFn params in queryKey
-
query-key-factory
-
Use factory pattern for consistent key generation
-
query-select-transforms
-
Use select option for data transformations
-
query-status-check-order
-
Check data first, then error, then loading
-
query-tracked-properties
-
Only destructure properties you use
-
query-placeholder-vs-initial
-
Know when to use each approach
-
query-dependent-enabled
-
Use enabled option for dependent queries
- Mutations & Updates (CRITICAL)
-
mutation-prefer-mutate
-
Use mutate() with callbacks over mutateAsync()
-
mutation-invalidation
-
Invalidate queries after mutations
-
mutation-direct-cache-update
-
Update cache directly when appropriate
-
mutation-optimistic-updates
-
Show success immediately, rollback on failure
-
mutation-callback-separation
-
Query logic in hook, UI effects in component
- Caching Strategy (HIGH)
-
cache-stale-time
-
Set appropriate staleTime for your domain
-
cache-refetch-triggers
-
Keep refetch triggers enabled in production
- WebSocket Integration (HIGH)
-
websocket-event-invalidation
-
Use events to trigger invalidation
-
websocket-stale-time-infinity
-
Set staleTime: Infinity for WS-managed data
-
websocket-reconnection
-
Invalidate stale queries on reconnect
- TypeScript Integration (MEDIUM)
-
typescript-infer-dont-specify
-
Let TypeScript infer, type the queryFn
-
typescript-zod-validation
-
Use Zod for runtime validation
- Testing Patterns (MEDIUM)
-
testing-fresh-client
-
Create fresh QueryClient per test
-
testing-msw-mocking
-
Use MSW for network mocking
- Common Pitfalls (MEDIUM)
-
troubleshoot-copy-to-state
-
Never copy query data to local state
-
troubleshoot-missing-key-deps
-
Include all dependencies in query key
-
troubleshoot-fetch-not-reject
-
Handle HTTP errors with fetch
- Migration to v5 (HIGH)
-
migration-cache-time-to-gc-time
-
cacheTime renamed to gcTime
-
migration-query-callbacks-removed
-
onSuccess/onError/onSettled removed from useQuery
-
migration-suspense-hooks
-
New useSuspenseQuery, useSuspenseInfiniteQuery hooks
Core Mental Model
-
React Query is NOT a data fetching library - it's an async state manager
-
Server state != Client state - never mix them in global state managers
-
Stale-while-revalidate - show cached data immediately, fetch in background
-
Query keys are dependencies - include all variables used in queryFn
How to Use
Read individual rule files for detailed explanations and code examples:
rules/query-key-factory.md rules/mutation-invalidation.md rules/websocket-event-invalidation.md
Each rule file contains:
-
Brief explanation of why it matters
-
Incorrect code example
-
Correct code example
Full Compiled Document
For the complete guide with all rules expanded: AGENTS.md