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 root swr package surface: default useSWR, named exports such as SWRConfig, 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, including FetcherResponse, BareFetcher, Fetcher, CacheData, and the internal GlobalState tuple that explains how cache, fetch, mutation, preload, and subscription state are coordinated.
  • test/use-swr-integration.test.tsx — Exercises the runtime behavior of useSWR: 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, including SWRConfig, useSWRConfig().cache, SWRResponse data nullability under Suspense and fallbackData, and configuration values such as fallback and cacheData.

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

SurfaceWhat it representsSource-backed notes
default export useSWRCore React hook imported from swrThe root entrypoint imports ./use-swr and exports it as default.
keyRequest and cache identityType tests cover strings, objects, tuples, readonly tuples, conditional keys, and function keys.
fetcherFunction that produces dataFetcherResponse<Data> may be Data or Promise<Data>; typed fetchers receive the inferred key argument.
optionsPer-hook SWRConfigurationIntegration and type tests cover revalidateOnMount, revalidateIfStale, revalidateOnFocus, revalidateOnReconnect, fallbackData, and suspense.
dataCurrent cached or fetched valueInitially may be undefined; can be non-optional in typed Suspense or fallback configurations.
isLoadingWhether the initial request is still loadingTested with fallback and disabled revalidation.
isValidatingWhether SWR is currently validating freshnessTested alongside isLoading in fallback and disabled revalidation scenarios.
errorFetcher failure statePart of the public response concept and error generic, with error typing represented by SWRResponse<Data, Error, Options>.
mutateBound cache updater on the hook responseThe 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.