Overview

Use TanStack Query for any React app with mutations, optimistic updates, paginated lists, or background refetch logic. Use SWR when the app is small, read-mostly, and already on Vercel where SWR’s defaults align with the platform. TanStack Query is the larger toolset; SWR is the lighter pattern. Both manage server state, not client state; pair either with Zustand or Redux for client state. See react-state-management for the wider rule set.

When TanStack Query wins

TanStack Query is the right pick for any React app with non-trivial cache, mutations, or background sync behavior.

  • Mutations: useMutation with onSuccess, onError, and invalidateQueries is the canonical pattern. SWR has mutate but lacks the lifecycle hooks; teams end up writing wrappers.
  • Optimistic updates: useMutation({ onMutate, onError, onSettled }) gives a typed rollback path. SWR optimistic UI is doable but the API is thinner.
  • Query keys are arrays with structural equality; ['post', id] invalidates only that post. SWR’s string keys force string concatenation conventions.
  • DevTools are best-in-class: see every active query, its cache state, last fetch time, and stale status. SWR DevTools exist but are less mature.
  • Pagination, infinite scroll, prefetching, and dependent queries are first-class: useInfiniteQuery, prefetchQuery, enabled flag.
  • Works outside React: @tanstack/query-core runs in Vue, Solid, and Svelte. Same mental model across the stack.
  • Suspense and Server Components support is stable in v5; SWR’s Suspense story is functional but quieter.

When SWR wins

SWR is the right pick for small read-mostly apps, especially those already on Vercel.

  • Smaller surface: useSWR(key, fetcher) is the whole API for 80 percent of use cases. New contributors are productive in an afternoon.
  • Bundle: SWR is roughly 4 KB gzipped; TanStack Query is 13 to 15 KB. On a content site with one or two data hooks, that gap shows up in Time-to-Interactive.
  • Vercel alignment: SWR is Vercel’s library. Examples in the Next.js docs default to it; Vercel-hosted templates ship it pre-wired. The integration cost is zero.
  • Stale-while-revalidate semantics map cleanly to the HTTP cache header pattern. If the API already sets Cache-Control: stale-while-revalidate, SWR mirrors it.
  • Focus revalidation and reconnect refetch are default-on with sensible behavior; TanStack Query has the same but exposes more knobs to misconfigure.
  • For a dashboard with a few read endpoints and no mutations: SWR is the smaller pick by every measure.

Trade-offs at a glance

DimensionTanStack QuerySWR
Bundle (gzipped)13 to 15 KB4 KB
Query keysArrays with structural equalityStrings or arrays via the key function
MutationsFirst-class with lifecycle hooksmutate() plus manual wiring
Optimistic updatesTyped; rollback path baked inManual; less ergonomic
DevtoolsExcellent; visualizes every queryFunctional; smaller feature set
Infinite scrolluseInfiniteQueryuseSWRInfinite
SuspenseStable in v5Supported; less documented
Server ComponentsPre-fetch and hydrate pattern documentedWorks; less canonical guidance
Cross-frameworkReact, Vue, Solid, SvelteReact (and Next.js)
Hiring familiarityHigh in React Native and dashboard teamsHigh in Next.js teams
Sweet spotApps with mutations and complex cacheRead-mostly content and dashboards

Migration cost

SWR-to-TanStack Query is the common direction once mutations or invalidation logic grows. The reverse is rare.

  • SWR to TanStack Query: replace useSWR(key, fetcher) with useQuery({ queryKey, queryFn }) and mutate(key) with queryClient.invalidateQueries({ queryKey }). The shapes are similar enough that a codemod handles roughly 70 percent. Plan one engineer-day per 30 hooks.
  • TanStack Query to SWR: only worth it on a small app where the bundle line item shows up. Rewrite mutations to imperative mutate() calls and drop most lifecycle code. Plan one engineer-day per 30 hooks.
  • Cheaper path: stay on the current library. The pain that justifies the switch usually shows up at the same time as a feature redesign; bundle the rewrite into that.

Recommendation

  • New React app with any mutations beyond a single form: TanStack Query.
  • New small Next.js app on Vercel that is mostly reads: SWR. The defaults align.
  • Dashboard with infinite scroll, optimistic edits, or background sync: TanStack Query.
  • Marketing site with one or two data hooks: neither; use Server Components and skip client cache; see server-vs-client-components.
  • React Native app: TanStack Query. The DevTools and offline patterns are documented for mobile.
  • Existing SWR codebase that grew complex: migrate the mutations only, leave reads on SWR. Two libraries coexist fine.
  • See react-state-management for the wider state strategy and zustand-vs-redux for the client-state pair.