Why SWR?
SWR (Stale-While-Revalidate) is derived from the HTTP caching invalidation strategy popularised by RFC 5861. Its philosophy is centered on immediate UI feedback: show the user the cached (stale) data first, send the fetch request (revalidate), and finally come with the up-to-date data. It strikes a balance between simplicity and performance.
- Lightweight & Fast: Significantly smaller bundle size compared to competitors, making it ideal for performance-critical applications.
- Automatic Revalidation: Keeps data fresh by revalidating on window focus, network reconnection, or at specified intervals.
- Focus on UX: The "cache first, update later" strategy ensures the UI feels snappy and responsive, eliminating blank loading states for returning users.
- Deduplication: Automatically prevents duplicate requests for the same key, optimizing network traffic.
- Backend Agnostic: Accepts any function that returns a promise, supporting REST, GraphQL, or any async data source.
Code Snippet
SWR's API is intentionally minimal. It relies on a global or local fetcher function and a key string (or array) to identify data.
import useSWR from 'swr'
// A simple wrapper around the native fetch API
const fetcher = (...args) => fetch(...args).then(res => res.json())
function Profile() {
// 'key' is the URL, which is passed to the fetcher
const { data, error, isLoading } = useSWR('/api/user', fetcher, {
refreshInterval: 3000, // Optional: Polling every 3 seconds
revalidateOnFocus: true // Optional: Re-fetch when window gets focus
})
if (error) return <div>Failed to load</div>
if (isLoading) return <div>Loading...</div>
return (
<div>
<h1>Hello, {data.name}!</h1>
<p>Status: {data.status}</p>
</div>
)
}
This snippet demonstrates the core hook. The fetcher logic is decoupled, and the component automatically handles the loading, error, and data states with built-in revalidation behaviors.
Pros and Cons
No library is perfect; understanding the trade-offs is key to selecting the right tool.
Pros
- Tiny Bundle Size: Weighs in at just a few kilobytes, adding negligible overhead to your application.
- Simplicity: The API surface is extremely small and easy to learn; you can master the basics in minutes.
- Next.js Integration: Being a Vercel product, it aligns perfectly with Next.js patterns and server-side rendering workflows.
- Smart Error Retry: Uses exponential backoff algorithms to handle network errors gracefully.
Cons
- Limited Mutation Features: While
mutateexists, it offers fewer built-in utilities for complex optimistic updates compared to TanStack Query. - Less Granular Cache Control: Managing the cache directly or debugging it is less transparent than with TanStack Query's DevTools.
- Feature Gap: lacks some "enterprise" features like dependent queries or paginated queries (though
useSWRInfinitecovers some of this) in a standardized way.
Comparison with Other Data Fetching Libraries
The table below outlines the positioning differences between SWR and other popular libraries to help you make an informed decision:
| Library | Design Philosophy | Best For | Pain Points |
|---|---|---|---|
| SWR | "Lightweight Speed" Minimalist implementation of the stale-while-revalidate strategy. | SaaS / Content Sites Apps needing fast, simple fetching without complex state orchestration. | Complex Mutations Manual cache manipulation for complex updates can be verbose. |
| TanStack Query | "The Kitchen Sink" Comprehensive server-state management with every feature imaginable. | Complex Applications Data-heavy dashboards with intricate caching and synchronization needs. | Bundle Size Substantially larger than SWR; overkill for simple blogs or landing pages. |
| Apollo Client | "Graph-Centric" Normalized caching specifically designed for the GraphQL graph. | GraphQL Ecosystem Teams fully committed to GraphQL requiring normalized data consistency. | Configuration High initial setup complexity and steep learning curve. |