useSWR
Purpose and Scope
useSWR is the primary hook exported by the swr package. It is the default import readers use when a React component needs remote data, cached data, loading state, error state, validation state, and a way to update the cached value. In the package entrypoint, src/index/index.ts imports the implementation from ./use-swr and re-exports it as the package default, while also exporting the companion configuration and cache APIs that commonly surround hook usage. That makes import useSWR from 'swr' the central public path for the core hook rather than a convenience alias layered on top of another package.
Sources: src/index/index.ts, src/_internal/types.ts
This reference explains the hook from the viewpoint of an application author: what arguments it accepts, what the response object represents, how TypeScript infers data and key types, and what runtime behavior is validated by the integration tests. It intentionally stays focused on the core hook. useSWRInfinite, useSWRMutation, useSWRSubscription, and useSWRImmutable extend or specialize the model, but the same vocabulary of keys, fetchers, cache state, revalidation, and configuration starts here.
Sources: src/index/index.ts, test/use-swr-integration.test.tsx
Relevant Source Files
src/index/index.ts— Defines the rootswrpackage surface: defaultuseSWR, named exports such asSWRConfig,useSWRConfig,mutate,preload, and the public TypeScript types re-exported from the internal package.src/_internal/types.ts— Defines shared public and internal types used by the hook surface, includingFetcherResponse,BareFetcher,Fetcher,CacheData, and the internalGlobalStatetuple that explains how cache, fetch, mutation, preload, and subscription state are coordinated.test/use-swr-integration.test.tsx— Exercises the runtime behavior ofuseSWR: initial undefined data, async fetchers, function keys, revalidation-on-mount settings, fallback data, loading and validating flags, and request deduplication.test/type/fetcher.ts— Verifies TypeScript inference for fetchers with string keys, object keys, tuples, readonly tuples, conditional keys, function keys, and generic data/error declarations.test/type/config.tsx— Verifies configuration and response typing, includingSWRConfig,useSWRConfig().cache,SWRResponsedata nullability under Suspense andfallbackData, and configuration values such asfallbackandcacheData.
API Components
The root entrypoint exposes useSWR as the default export and several adjacent APIs as named exports. SWRConfig provides React context configuration, useSWRConfig reads the current configuration and scoped cache, mutate updates cache entries, preload starts fetch work before a hook renders, and unstable_serialize serializes keys for advanced cache work. The same entrypoint re-exports the public type vocabulary used throughout the library: SWRConfiguration, SWRConfigValue, Key, KeyLoader, Fetcher, BareFetcher, SWRHook, SWRResponse, KeyedMutator, Cache, ScopedMutator, Middleware, State, Arguments, and mutation-related types.
Sources: src/index/index.ts
A practical signature for the hook is: useSWR<Data, Error, Options>(key, fetcher?, options?) => SWRResponse<Data, Error, Options>. The exact overloads are represented in the public type files rather than written in src/index/index.ts, but the tests show the accepted calling forms. A key can be a string, object, tuple, readonly tuple, conditional expression that resolves to a key or null/false, or a function returning a key. A fetcher can be passed directly as the second argument, omitted when a configured default fetcher exists, or paired with a per-hook configuration object.
Sources: test/type/fetcher.ts, test/type/config.tsx
The response object is the component’s current view of SWR state. Integration tests use data, isLoading, and isValidating, while typical application usage also handles error and the bound cache updater exposed through the response type. The important behavior is that data may be absent before the first successful fetch unless the hook is configured to have blocking data. The type tests explicitly validate that SWRResponse['data'] becomes non-optional for certain suspense: true and fallbackData configurations, while a plain hook call can still produce undefined data during the first render.
Sources: src/_internal/types.ts, test/type/config.tsx, test/use-swr-integration.test.tsx
Arguments and Type Inference
The first argument, the SWR key, identifies both the request and the cache entry. src/_internal/types.ts defines Fetcher<Data, SWRKey> as a conditional type tied to the key. If the key is a function that returns a value, the fetcher receives that returned value. If the key is null, undefined, or false, the fetcher type becomes never, matching the runtime idea that a disabled key should not cause a request. Otherwise, the fetcher receives the key value itself, preserving string literals, object shapes, and tuple shapes where TypeScript can retain them.
Sources: src/_internal/types.ts, test/type/fetcher.ts
The fetcher type tests demonstrate why this matters in day-to-day code. A call like useSWR('/api/user', key => key) preserves the literal '/api/user' as the fetcher parameter. Object keys preserve nested object structure. Tuple keys preserve tuple element types, and as const readonly tuples preserve readonly literal types. Conditional keys such as truthy() ? '/api/user' : null still allow the fetcher to receive the non-null key type, so application code can express “only fetch when ready” without losing useful fetcher inference.
Sources: test/type/fetcher.ts
Fetcher return values may be synchronous data or promises. The shared FetcherResponse<Data> type is defined as Data | Promise<Data>, and BareFetcher is the permissive escape hatch that accepts any arguments. Integration tests cover async fetchers by returning a delayed response and verifying that the component first renders without data, then rerenders with the resolved value. This means useSWR does not require a particular HTTP client: the fetcher is responsible for transport, parsing, authentication headers, and errors, while SWR is responsible for caching and coordinating render state around the result.
Sources: src/_internal/types.ts, test/use-swr-integration.test.tsx
Runtime Behavior
On an initial render without cached or fallback data, useSWR can return undefined data and later update the component when the fetcher resolves. The integration suite has a test that renders hello, during hydration and then hello, SWR after mount. That sequence is the most important mental model for the hook: rendering is allowed to proceed with the currently available value, then SWR revalidates and publishes fresh state. Components should branch on isLoading, error, or the presence of data rather than assuming the fetcher result is available immediately.
Sources: test/use-swr-integration.test.tsx
Keys can be functions, and those function keys participate in the same cache reuse model as direct keys. The integration tests show useSWR(() => sharedKey, () => 'SWR') resolving from the same shared key. Function keys are useful when a request depends on state that may not exist yet. If the function returns a real key, SWR can fetch or reuse the cache entry; if it resolves to a falsy disabled key, the typed fetcher contract indicates that no fetcher call is expected for that disabled state.
Sources: src/_internal/types.ts, test/use-swr-integration.test.tsx
Revalidation-on-mount options affect whether the fetcher runs for a mounted component. A test with revalidateOnMount: false confirms the fetch function is not called for the initial key. Another test changes the key after mount and then observes the fetcher result, showing that disabling mount revalidation does not permanently disable all future fetching. A key transition creates a new request identity, so the hook can fetch for the new key even when the initial mount was intentionally quiet.
Sources: test/use-swr-integration.test.tsx
Fallback data changes both user experience and type behavior. At runtime, a test with fallbackData: 'gab' and revalidateOnMount: true initially renders the fallback value and then replaces it with the fetcher result. Another test disables stale, focus, and reconnect revalidation while providing fallback data; in that case isLoading and isValidating are both false and the fetcher is not called. In type tests, fallbackData can make data non-optional when the options type is specific enough, which lets components avoid redundant undefined checks in carefully typed configurations.
Sources: test/use-swr-integration.test.tsx, test/type/config.tsx
Compact Reference
| Surface | What it represents | Source-backed notes |
|---|---|---|
default export useSWR | Core React hook imported from swr | The root entrypoint imports ./use-swr and exports it as default. |
key | Request and cache identity | Type tests cover strings, objects, tuples, readonly tuples, conditional keys, and function keys. |
fetcher | Function that produces data | FetcherResponse<Data> may be Data or Promise<Data>; typed fetchers receive the inferred key argument. |
options | Per-hook SWRConfiguration | Integration and type tests cover revalidateOnMount, revalidateIfStale, revalidateOnFocus, revalidateOnReconnect, fallbackData, and suspense. |
data | Current cached or fetched value | Initially may be undefined; can be non-optional in typed Suspense or fallback configurations. |
isLoading | Whether the initial request is still loading | Tested with fallback and disabled revalidation. |
isValidating | Whether SWR is currently validating freshness | Tested alongside isLoading in fallback and disabled revalidation scenarios. |
error | Fetcher failure state | Part of the public response concept and error generic, with error typing represented by SWRResponse<Data, Error, Options>. |
mutate | Bound cache updater on the hook response | The root package also exports global mutate and KeyedMutator types for cache updates. |
Sources: src/index/index.ts, src/_internal/types.ts, test/use-swr-integration.test.tsx, test/type/config.tsx
Configuration Interactions
useSWR can be used alone, but it is designed to cooperate with SWRConfig. The type tests import SWRConfig, useSWRConfig, and SWRConfigValue from swr, and verify that useSWRConfig().cache has the public Cache<any> type. They also validate that configuration values cannot be null, that callbacks must return configuration objects rather than arbitrary values, and that fallback may contain concrete values or promises. This is the type-level support for a common application pattern: set shared fetchers, fallback values, cache providers, or callbacks once, then keep individual useSWR calls small.
Sources: src/index/index.ts, test/type/config.tsx
The internal type definitions clarify why configuration has visible effects on hook return types. BlockingData<Data, Options> examines global Suspense, per-hook Suspense, and fallback data to decide whether data should be considered blocking and therefore defined. The tests make the edge cases explicit: a direct suspense: true call can infer non-optional data, but passing only a partial generic can lose some config inference because of TypeScript partial inference limitations. When a caller needs exact response nullability, the tests show the pattern of passing the configuration type parameter explicitly.
Sources: src/_internal/types.ts, test/type/config.tsx
Implementation and State Model
Although the root entrypoint hides the hook implementation behind ./use-swr, the shared types expose the major internal state buckets that the hook coordinates. GlobalState contains event revalidators, mutation timestamps, the fetch cache, the preload cache, a scoped mutator, a cache setter, and a cache subscriber. These pieces explain the behavior seen in tests: two hook instances with the same key can dedupe a request, cache updates can notify subscribers, preloaded responses can be consumed later, and mutations can be ordered against in-flight fetches.
Sources: src/_internal/types.ts, test/use-swr-integration.test.tsx
The integration suite includes a request deduplication scenario where two useSWR calls use the same key and fetcher in one component. The expected behavior is a single underlying fetch rather than duplicate network work. That behavior follows from the fetch cache and key-based state model: useSWR is not merely a useEffect wrapper around a fetcher, but a cache-aware hook that coordinates work across hook instances sharing a provider and serialized key.
Sources: src/_internal/types.ts, test/use-swr-integration.test.tsx
Usage Guidance and Next Steps
For a new component, start with the smallest useful call: choose a stable key, provide a fetcher that accepts that key, and branch on error, isLoading, and data. Use conditional keys when required inputs are missing, instead of placing conditions inside the fetcher. Add fallbackData when the component has server-provided or previously known data, and tune revalidateOnMount only when you deliberately want to suppress or force the first revalidation. When TypeScript inference matters, let the key and fetcher drive inference before reaching for explicit generics.
Sources: test/type/fetcher.ts, test/type/config.tsx, test/use-swr-integration.test.tsx
Read SWRConfig next when repeated options or global fetchers appear across many hooks. Read mutate when the component must update cached data after a user action. Read preload when a route or interaction can start a request before the component renders. If your data model is paginated, triggered by an imperative mutation, event-driven, or effectively immutable, move from this core reference to the specialized hook pages for useSWRInfinite, useSWRMutation, useSWRSubscription, or useSWRImmutable.