Overview
Use TanStack Query when an app has mutations, optimistic updates, paginated or infinite lists, or complex invalidation; use SWR when the app mostly reads and the one-hook API is enough. As of 2026-10-01 TanStack Query is at v5.104 and SWR at 2.5. Both cache server state; neither replaces a client-state store (zustand-vs-redux).
Comparison
| Dimension | TanStack Query v5 | SWR 2 |
|---|---|---|
| Core API | useQuery({ queryKey, queryFn }), useMutation | useSWR(key, fetcher), useSWRMutation |
| Keys | Arrays with structural matching; invalidateQueries({ queryKey }) by prefix | Key string, array, or function; mutate(key) |
| Mutations | Lifecycle (onMutate, onError, onSettled) and rollback pattern | useSWRMutation and mutate with optimisticData |
| Pagination | useInfiniteQuery, prefetchQuery, enabled for dependent queries | useSWRInfinite, conditional keys |
| Suspense and RSC | useSuspenseQuery; prefetch on the server and hydrate | Suspense option; fewer documented server patterns |
| Frameworks | React, Vue, Solid, Svelte, Angular (experimental package) | React |
| Size (gzipped, whole package) | About 14 KB | About 6 KB |
Pick TanStack Query when
Pick TanStack Query for apps where writes and cache coordination matter.
- Mutations that invalidate or update several queries, with optimistic UI and rollback.
- Infinite scroll, prefetching, dependent queries, and cache persistence.
- Query devtools to inspect cache state and staleness.
- The same model across React, Vue, Solid, or Svelte.
- Define reusable
queryOptionsobjects so keys and functions stay together.
Pick SWR when
Pick SWR when the app is small and read-heavy.
- A dashboard or content page with a few GET endpoints and few writes.
- Revalidate on focus and reconnect, and stale-while-revalidate behavior, with minimal setup.
- You prefer one small hook over a configured client.
Server Components first
Do not add either library for data a Server Component can fetch; see server-vs-client-components. Add a client cache only for interactive, frequently changing, or user-driven data.
Migrate
SWR to TanStack Query: replace useSWR(key, fetcher) with useQuery({ queryKey, queryFn }) and mutate(key) with queryClient.invalidateQueries({ queryKey }). Migrate mutation-heavy screens first, since reads on SWR keep working; the libraries coexist. Moving the other way is only worth it for bundle size on a small app. See react-state-management for state strategy.
FAQ
Should I use TanStack Query or SWR?
Use TanStack Query v5 when the app has mutations, optimistic updates, infinite lists, or complex invalidation. Use SWR 2 for small read-mostly apps where the one-hook API is enough.
Is SWR smaller than TanStack Query?
Yes; SWR is about 6 KB gzipped for the whole package, against about 14 KB for TanStack Query. Moving from TanStack Query to SWR is only worth it for bundle size on a small app.
Do I need TanStack Query with React Server Components?
Not for data a Server Component can fetch. Add a client cache only for interactive, frequently changing, or user-driven data.
Can TanStack Query replace Redux or Zustand?
No; both libraries cache server state, and neither replaces a client-state store. See zustand-vs-redux for client state.