← Back to articles

React Query vs SWR vs RTK Query: Best Data Fetching Library (2026)

Data fetching in React is a solved problem — you just have to pick which solution. TanStack Query (formerly React Query), SWR, and RTK Query dominate the space. Each makes a different tradeoff between features, simplicity, and ecosystem integration.

Quick Comparison

FeatureTanStack QuerySWRRTK Query
ByTanner LinsleyVercelRedux team
Bundle size~13KB~4KB~13KB (+ Redux)
CachingAdvancedGoodAdvanced
DevToolsExcellentBasicRedux DevTools
MutationsFirst-classBasicFirst-class
Optimistic updatesBuilt-in helpersManualBuilt-in
Infinite queriesBuilt-inBuilt-inManual
PaginationBuilt-inBuilt-inBuilt-in
PrefetchingYesYesYes
SSR supportExcellentGoodGood
Offline supportBuilt-inManualManual
Dependent queriesYes (enabled option)Yes (conditional)Yes
Requires ReduxNoNoYes

TanStack Query (React Query): The Feature King

TanStack Query is the most feature-complete data fetching library. It handles caching, synchronization, pagination, optimistic updates, offline support, and more — all with excellent DevTools.

Strengths

Comprehensive caching. Smart cache invalidation, background refetching, stale-while-revalidate, garbage collection, and structural sharing. You rarely think about caching bugs.

const { data, isLoading, error } = useQuery({
  queryKey: ['todos', userId],
  queryFn: () => fetchTodos(userId),
  staleTime: 5 * 60 * 1000, // 5 minutes
});

Mutations with cache updates. Mutate data and update the cache optimistically — the UI reflects changes before the server confirms.

const mutation = useMutation({
  mutationFn: createTodo,
  onMutate: async (newTodo) => {
    await queryClient.cancelQueries({ queryKey: ['todos'] });
    const previous = queryClient.getQueryData(['todos']);
    queryClient.setQueryData(['todos'], (old) => [...old, newTodo]);
    return { previous };
  },
  onError: (err, newTodo, context) => {
    queryClient.setQueryData(['todos'], context.previous);
  },
  onSettled: () => {
    queryClient.invalidateQueries({ queryKey: ['todos'] });
  },
});

DevTools. The best debugging experience in the React data-fetching space. Visualize cache state, query status, and refetch behavior in real-time.

Framework agnostic. Works with React, Vue, Svelte, Solid, and Angular (TanStack Query, not just React Query).

Offline support. Built-in mutation pausing and resuming for offline-first applications.

Weaknesses

  • Larger bundle than SWR (~13KB vs ~4KB)
  • More concepts to learn (query keys, invalidation, mutation lifecycle)
  • Overkill for simple apps with few API calls
  • No built-in API normalization (unlike RTK Query)

Best For

Most React applications. The default choice when you need robust data fetching with caching. Especially strong for apps with mutations, optimistic updates, or offline requirements.

SWR: The Simple Choice

SWR (stale-while-revalidate) is Vercel's data fetching library. It's minimal, fast, and gets out of your way.

Strengths

Tiny bundle. ~4KB gzipped. The smallest option by far.

Simple API. One hook covers most use cases:

const { data, error, isLoading } = useSWR('/api/todos', fetcher);

Global configuration. Set defaults once, apply everywhere:

<SWRConfig value={{ fetcher, refreshInterval: 3000 }}>
  <App />
</SWRConfig>

Automatic revalidation. Refetches on focus, reconnect, and interval by default. Data stays fresh without manual cache management.

Next.js integration. Natural fit with Next.js (same team). Works well with App Router and Server Components.

Weaknesses

  • Basic mutations. No built-in mutation hooks. You handle mutations manually and call mutate() to update the cache.
  • No DevTools (community alternatives exist but aren't as good as TanStack Query's)
  • Less control over cache. Simpler caching means fewer options for complex scenarios.
  • Optimistic updates are manual. You can do them, but there's no built-in helper.
  • No offline support out of the box.

Best For

Simple applications, Next.js projects, or teams who value minimalism. Great when your data fetching is mostly read-heavy with few mutations.

RTK Query: The Redux Integration

RTK Query is Redux Toolkit's data fetching solution. It generates hooks from API definitions and integrates directly with the Redux store.

Strengths

API definition approach. Define your entire API once, get typed hooks automatically:

const api = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
  tagTypes: ['Todo'],
  endpoints: (builder) => ({
    getTodos: builder.query<Todo[], void>({
      query: () => 'todos',
      providesTags: ['Todo'],
    }),
    addTodo: builder.mutation<Todo, Partial<Todo>>({
      query: (body) => ({ url: 'todos', method: 'POST', body }),
      invalidatesTags: ['Todo'],
    }),
  }),
});

export const { useGetTodosQuery, useAddTodoMutation } = api;

Automatic cache management. Tag-based invalidation automatically refetches affected queries when mutations succeed. Define relationships once, never manually invalidate.

Redux integration. If you're already using Redux, RTK Query shares the store. One state management solution for everything.

Response normalization. Entity adapter integration for normalized cache structure — prevents duplicate data and enables efficient updates.

Code generation. Generate RTK Query API definitions from OpenAPI/Swagger specs automatically.

Weaknesses

  • Requires Redux. If you're not using Redux, adding it just for RTK Query is heavy.
  • Learning curve. createApi, tags, cache lifecycle, middleware — there's a lot of Redux-specific concepts.
  • Boilerplate. API definitions are verbose compared to TanStack Query or SWR hooks.
  • Bundle size. ~13KB for RTK Query + ~13KB for Redux Toolkit + ~5KB for React-Redux.
  • Less community content than TanStack Query or SWR.

Best For

Applications already using Redux. RTK Query eliminates the boilerplate of writing thunks/sagas for data fetching. Don't adopt Redux just for RTK Query.

Decision Framework

Your SituationChoose
New project, no ReduxTanStack Query
Simple app, few API callsSWR
Already using ReduxRTK Query
Next.js projectSWR or TanStack Query
Many mutations + optimistic updatesTanStack Query
Bundle size is criticalSWR
Need DevTools for debuggingTanStack Query
Offline-first appTanStack Query
OpenAPI/Swagger APIRTK Query (code generation)

FAQ

Can I use these with React Server Components?

Yes. All three work in client components. For Server Components, use fetch directly and pass data to client components that use these libraries for interactivity and mutations.

Do I still need useState/useEffect for data fetching?

No. Any of these libraries replaces the useEffect + useState + loading/error state pattern. This is their primary value.

Can I switch between them?

Yes, but it requires rewriting your data-fetching hooks. The concepts are similar (cache, revalidation, mutations), so the mental model transfers even if the API doesn't.

What about Apollo Client for GraphQL?

If your API is GraphQL, Apollo Client or urql are the standard choices. TanStack Query and SWR work with GraphQL too (use graphql-request as the fetcher), but Apollo's normalized cache is designed for GraphQL's graph structure.

The Verdict

  • TanStack Query for most React applications. Best features, best DevTools, best community.
  • SWR for simple apps, Next.js projects, or when bundle size matters. Less power, less complexity.
  • RTK Query for Redux-based applications. Don't adopt Redux just for RTK Query.

If you're unsure, start with TanStack Query. It scales from simple to complex without hitting walls.

Get AI tool guides in your inbox

Weekly deep-dives on the best AI coding tools, automation platforms, and productivity software.