SWR and TanStack Query both cache and deduplicate requests in React, but they differ in size and scope. SWR is minimal and focused on stale-while-revalidate fetching, while TanStack Query adds mutations, devtools, and more granular cache controls. This guide compares them side by side.
The core difference in a table
The libraries solve the same problem with different scopes. SWR stays small and centers on the fetch, while TanStack Query is a broader toolkit that also handles writes.
| Feature | SWR | TanStack Query |
|---|---|---|
| Package | swr | @tanstack/react-query |
| Core hook | useSWR(key, fetcher) | useQuery({ queryKey, queryFn }) |
| Mutations | global mutate helper | useMutation and invalidateQueries |
| Devtools | none built in | official devtools package |
| Cache options | dedupingInterval, revalidate flags | staleTime, gcTime, retry |
The table shows the main gap. SWR has no built-in mutation hook, while TanStack Query treats queries and mutations as first-class concepts.
For a read-only dashboard that gap barely matters, and for an app that writes data often it is the deciding factor. The tradeoff is size and surface area: SWR gives you less to learn, and TanStack Query gives you more built-in answers.
How the basic query compares
For a plain read, the code looks nearly identical. SWR takes a key string and a fetcher function, while TanStack Query takes an options object with a key array and a query function.
import useSWR from "swr";
function Posts() {
const { data, error, isLoading } = useSWR("/api/posts", fetcher);
if (isLoading) return <p>Loading posts...</p>;
if (error) return <p>Could not load posts.</p>;
return <ul>{data.map((post) => <li key={post.id}>{post.title}</li>)}</ul>;
}The fetcher is any function that returns JSON, usually a wrapper around fetch. SWR returns data, error, and isLoading, and it deduplicates requests that use the same key automatically. The page also revalidates on focus and reconnect, which is the behavior the name describes.
import { useQuery } from "@tanstack/react-query";
function Posts() {
const { isPending, isError, data, error } = useQuery({
queryKey: ["posts"],
queryFn: fetchPosts,
});
if (isPending) return <p>Loading posts...</p>;
if (isError) return <p>Could not load posts: {error.message}</p>;
return <ul>{data.map((post) => <li key={post.id}>{post.title}</li>)}</ul>;
}TanStack Query returns the same three concepts under different names: isPending for the first load, isError, and data. The key is an array rather than a string, which allows more structure. The query key is explained in useQuery explained.
What TanStack Query adds
TanStack Query's extra surface shows up when the app grows. It ships a mutation hook for writes, official devtools, and more granular options such as staleTime and gcTime.
- useMutation and invalidateQueries handle writes and the refetch that follows.
- The devtools let you inspect and edit the cache while developing.
- staleTime and gcTime tune freshness and memory separately.
- Retry, pagination, and infinite query helpers are built in.
SWR covers reads very well and leaves writes to your own functions or its global mutate helper. Both libraries share the same stale-while-revalidate idea, so the mental model carries over.
None of these extras are missing from SWR by accident; they are simply outside its minimal scope. The TanStack setup behind those features is covered in how to set up TanStack Query in React.
Which should you choose?
Choose SWR when the app is mostly reads and you want a small, focused dependency. Choose TanStack Query when writes, devtools, and fine-grained cache control are part of the job.
A read-heavy dashboard with a few endpoints is a strong fit for SWR. An app with forms, optimistic updates, and many related endpoints is a stronger fit for TanStack Query.
For one or two requests on a page, neither library is required; plain state or a custom Hook is enough. The libraries earn their place once several components share the same data.
SWR also has a smaller API to learn, which matters for a small team moving fast. If you already use one and it covers your cases, switching is rarely worth it. Both replace the manual Effect fetch described in how to fetch API data in React.
Rune AI
Key Insights
- SWR is minimal; TanStack Query is a larger toolkit.
- Both dedupe and cache by key.
- SWR uses useSWR, TanStack Query uses useQuery.
- TanStack Query adds useMutation and devtools.
- Choose by writes and cache-control needs.
Frequently Asked Questions
Which is smaller, SWR or TanStack Query?
Does SWR have mutations?
Can I switch between the two later?
Conclusion
SWR is the small, read-focused option, and TanStack Query is the broader toolkit with mutations, devtools, and fine-grained cache control. Pick SWR for simple reads and TanStack Query when writes and cache tuning matter.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.