| 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 |