SWR: React Hooks for Data Fetching
SWR is a lightweight and performant React Hooks library for remote data fetching, currently at version 2.4.1. It implements the 'stale-while-revalidate' cache invalidation strategy, popularized by HTTP RFC 5861, to provide an always-fresh and responsive user interface. Maintained by Vercel, SWR ensures components receive a continuous stream of data updates automatically. It offers robust features like built-in caching, request deduplication, real-time revalidation on focus/network recovery, polling, pagination, local mutation for optimistic UI, smart error retry, and comprehensive TypeScript support. Its predictable release cadence, with frequent minor updates and patches, ensures ongoing stability and feature enhancements. Key differentiators include its simplicity with a single `useSWR` hook, strong focus on performance and developer experience, and broad support for modern React features like Suspense.
Common errors
-
Error: useSWR is not a function
cause Attempting to import `useSWR` as a named export when it is a default export.fixChange your import statement from `import { useSWR } from 'swr'` to `import useSWR from 'swr'`. -
TypeError: Cannot read properties of undefined (reading 'name') at Profile
cause Attempting to access `data` before it's loaded, especially when not using Suspense, or when `data` is `undefined` due to an error or initial loading state.fixAlways check for `isLoading` or `error` before accessing `data`. Example: `if (isLoading) return <div>loading...</div>; if (error) return <div>failed to load</div>; return <div>hello {data.name}!</div>`. -
Failed to compile. Module parse failed: Cannot assign to read only property 'exports' of object '#<Object>'
cause Mixing CommonJS `require()` with an ESM-first library like SWR, or incorrect bundler configuration for ESM modules.fixEnsure your project uses `import` statements for SWR. If using Node.js, confirm `"type": "module"` is set in your `package.json` or use `.mjs` extensions for files importing SWR. Check bundler configuration (e.g., Webpack, Rollup) to correctly resolve ESM modules. -
Type 'undefined' is not assignable to type '...' when using data from useSWR with TypeScript and Suspense is enabled.
cause When `suspense: true` is enabled, SWR guarantees `data` will always be defined at the component render point, but TypeScript might still infer it as `data | undefined` without proper configuration.fixConfigure TypeScript by ensuring `"compilerOptions": { "exactOptionalPropertyTypes": true }` is not set to `false` if it conflicts. More practically, if `suspense: true` is used, TypeScript should infer `data` as non-nullable. If it doesn't, ensure your TypeScript version is compatible and explicitly assert type if necessary (e.g., `data!.name`), though this should ideally be avoided.
Warnings
- breaking SWR v2 introduced breaking changes related to the return shape of the `useSWR` hook, error handling, and `mutate` API. Specifically, `isValidating` was replaced with `isLoading` for initial data fetching state, and the `mutate` function no longer accepts `shouldRevalidate` as a direct boolean argument but as part of an options object.
- breaking SWR transitioned to an ESM-first package distribution starting from v2. While CJS bundles are still provided for backward compatibility, ESM is the recommended way to import. Users with older tooling or specific CommonJS setups might face issues.
- gotcha When using `useSWRImmutable`, global `refreshInterval` settings might still trigger revalidations. This can lead to unexpected data refreshes for data intended to be static.
- breaking Multiple critical RCE (Remote Code Execution) vulnerabilities (CVE-2025-55182, CVE-2025-55183, CVE-2025-55184) were identified and patched in version 2.3.8. These vulnerabilities could allow an attacker to execute arbitrary code.
- gotcha When `useSWR` is enabled in Suspense mode (`suspense: true`), the `data` property will never be `undefined` (it will throw a Promise instead). Components must be wrapped in `<Suspense>` boundary. Misunderstanding this can lead to 'cannot read properties of undefined' errors.
Install
-
npm install swr -
yarn add swr -
pnpm add swr
Imports
- useSWR
import { useSWR } from 'swr'import useSWR from 'swr'
- SWRConfig
import SWRConfig from 'swr'
import { SWRConfig } from 'swr' - useSWRImmutable
import useSWRImmutable from 'swr'
import { useSWRImmutable } from 'swr' - Key
import { Key } from 'swr'import type { Key } from 'swr'
Quickstart
import useSWR from 'swr';
const fetcher = async (url) => {
const res = await fetch(url);
if (!res.ok) {
const error = new Error('An error occurred while fetching the data.');
error.info = await res.json();
error.status = res.status;
throw error;
}
return res.json();
};
function UserProfile() {
// In a real application, you might use an environment variable for the base URL
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL ?? 'https://api.example.com';
const userId = '123'; // Example user ID
const { data, error, isLoading } = useSWR(`${API_BASE_URL}/users/${userId}`, fetcher);
if (error) return <div>Failed to load user data: {error.message}</div>;
if (isLoading) return <div>Loading user profile...</div>;
return (
<div>
<h1>User Profile</h1>
<p>Name: {data.name}</p>
<p>Email: {data.email}</p>
</div>
);
}
// Example of how to render it (e.g., in a React component tree)
// function App() {
// return <UserProfile />;
// }
// export default App;