SWRConfig

Purpose and Scope

SWRConfig is the React provider used to define SWR behavior for a subtree of hooks. Instead of passing the same fetcher, cache policy, retry behavior, fallback values, and callbacks to every useSWR call, applications can place shared configuration at a boundary and let descendant hooks read it from context. The official global fetcher example frames this as setting up the fetcher globally rather than repeating a per-hook call, and the repository code exposes that provider from the main swr package entrypoint.

Sources: src/index/config.ts, src/_internal/utils/config.ts, test/use-swr-config.test.tsx

The provider matters because SWR is cache-oriented: several hooks can participate in the same stale-while-revalidate lifecycle only when they agree on key identity, cache storage, mutation scope, and revalidation rules. A configuration boundary is therefore more than a convenience wrapper. It defines how a part of the application shares data, how it reacts to focus or reconnect events, how errors are retried, and which initial data can satisfy rendering before a network request completes.

Sources: src/_internal/utils/config.ts, src/_internal/types.ts, test/use-swr-config.test.tsx

Relevant Source Files

  • src/index/config.ts — marks the browser-facing module as client code and re-exports the internal SWRConfig implementation as the public SWRConfig export from the main package.
  • src/_internal/utils/config.ts — constructs the default configuration, default cache, default scoped mutate, comparison function, retry behavior, event callbacks, revalidation switches, timeout values, and fallback map.
  • src/_internal/types.ts — defines configuration-adjacent public and internal types, including cache data, fetcher responses, cache shape, scoped mutator, and the state tuple used by SWR internals.
  • test/use-swr-config.test.tsx — validates runtime configuration behavior such as context fetchers, refresh intervals, pause handling, SWRConfig.defaultValue, and server-produced cache data consumed with Suspense.
  • test/use-swr-config-callbacks.test.tsx — verifies that configuration callbacks such as success, error, and retry handlers use the latest callback version after rerendering.
  • test/type/config.tsx — validates TypeScript behavior for SWRConfig, useSWRConfig, fallback data, cache data, Suspense, and invalid provider values.

System-to-Code Mapping

The public package surface is intentionally thin for this component. The file src/index/config.ts contains a client directive and re-exports SWRConfig from the internal module. That means application code imports SWRConfig from swr, while the implementation can live with other internal context and cache utilities. This separation keeps the public API stable and lets build outputs provide the same named export through the package entrypoint without forcing users to know about internal module layout.

Sources: src/index/config.ts

The default behavior is assembled in src/_internal/utils/config.ts. SWR initializes a default cache with initCache(new Map()), exports the resulting cache and scoped mutate, and uses dequal as the default data comparison function. The default configuration merges core defaults with the web preset, so browser event behavior can be enabled by default while still allowing individual applications or subtrees to override values through SWRConfig. This file is the best source for understanding what happens when no provider is present.

Sources: src/_internal/utils/config.ts

src/_internal/types.ts shows why configuration is tied to cache and mutation mechanics. The GlobalState tuple contains event revalidators, mutation timestamps, fetch cache, preload cache, a scoped mutator, a cache setter, and a cache subscriber. The CacheData type represents server-produced data that can be consumed by SWRConfig on the client. The FetcherResponse type allows either direct data or a promise, which explains why fallback and cache-data paths can participate in both synchronous and asynchronous render flows.

Sources: src/_internal/types.ts

Configuration Values and Defaults

A default SWRConfig value exists even when an application does not render a provider. Tests assert that SWRConfig.defaultValue is defined, and type tests assign that default value to a full configuration type. The default callbacks are no-ops except for retry behavior, which uses an exponential backoff based on the retry count and errorRetryInterval. If errorRetryCount is set and the current retry count exceeds it, the default retry handler stops scheduling another revalidation.

Sources: src/_internal/utils/config.ts, test/use-swr-config.test.tsx, test/type/config.tsx

Important default switches include revalidation on focus, revalidation on reconnect, revalidation when stale, and retry on error. The default timing values include a focus throttle interval, deduping interval, loading timeout, and error retry interval, with slower connection conditions increasing selected timeouts. The default isPaused function returns false, so requests are allowed unless a provider or per-hook option changes that decision. The default fallback object is empty, making fallback data opt-in.

Sources: src/_internal/utils/config.ts

The provider value may be an object, undefined, or a function returning a configuration object. Type tests reject null, reject callbacks that return null, and reject callbacks that return non-configuration values. This is useful when building nested providers: a callback-style value can derive settings from the parent configuration, while an object-style value can directly provide fields such as fallback, cacheData, or a fetcher. Type coverage also confirms that useSWRConfig().cache is exposed as a Cache<any>.

Sources: test/type/config.tsx

Runtime Behavior

A common provider task is installing a global fetcher. In the runtime tests, a component calls useSWR(key) without passing a fetcher directly, while renderWithConfig supplies a fetcher and interval settings. The hook reads configuration from context, hydrates with empty data, fetches on mount, and then refreshes according to the configured interval. This is the same pattern promoted by the global fetcher example: centralize transport behavior at the boundary and keep individual hooks focused on keys and rendering.

Sources: test/use-swr-config.test.tsx

isPaused is a stronger runtime control than an interval or manual mutation trigger. Tests configure a hook with revalidateOnMount, a short refresh interval, and an isPaused function. While paused, initial revalidation and subsequent bound mutate() revalidation attempts do not advance data or enter loading and validating states. After toggling the pause state off, revalidation proceeds again. This makes isPaused suitable for application-wide offline modes, hidden workflows, or temporary guards around invalid authentication state.

Sources: test/use-swr-config.test.tsx

SWR also supports server-produced data through configuration. The tests render an SWRConfig value containing cacheData, wrap a Suspense boundary, and verify the hook can consume server data without immediately revalidating on mount in that scenario. The related type test accepts a cacheData object keyed by request key. This is distinct from ordinary per-hook fallbackData: cacheData is modeled as a cache-shaped payload produced elsewhere and then consumed by the client provider boundary.

Sources: src/_internal/types.ts, test/use-swr-config.test.tsx, test/type/config.tsx

Callbacks and Fresh Closures

Configuration callbacks are part of the runtime contract, not just static options. Callback tests render a component with props, trigger success or error handling, rerender with different props, and then trigger another revalidation. The assertions confirm that onSuccess and onError observe the latest callback version rather than closing over the first render forever. This is important for React applications where callbacks may depend on current route state, analytics context, user identity, or other props that change without remounting the SWR hook.

Sources: test/use-swr-config-callbacks.test.tsx

The retry callback follows the same freshness rule. A test supplies onErrorRetry, records the current prop value, and calls the provided revalidate function with retry options. After rerendering, the scheduled retry observes the latest callback state when it runs. If you customize retry behavior, treat the callback as part of the revalidation pipeline: it receives the error, key, configuration, revalidate function, and retry options, and it is responsible for deciding whether and when another request should occur.

Sources: src/_internal/utils/config.ts, test/use-swr-config-callbacks.test.tsx

Compact Reference

Use SWRConfig from the main package when a subtree needs shared SWR behavior. Typical fields include a global fetcher, fallback, cacheData, callbacks such as onSuccess, onError, onErrorRetry, and behavior switches such as revalidateOnFocus, revalidateOnReconnect, revalidateIfStale, shouldRetryOnError, and isPaused. Timing fields from the default configuration include errorRetryInterval, focusThrottleInterval, dedupingInterval, and loadingTimeout. Provider values should be configuration objects, undefined, or functions that return configuration objects.

Sources: src/_internal/utils/config.ts, test/type/config.tsx

import useSWR, { SWRConfig } from 'swr'
 
const fetcher = (url: string) => fetch(url).then(res => res.json())
 
function App() {
  return (
    <SWRConfig value={{ fetcher, fallback: { '/api/user': { name: 'Ada' } } }}>
      <Profile />
    </SWRConfig>
  )
}
 
function Profile() {
  const { data, error, isLoading } = useSWR('/api/user')
  if (error) return <div>failed</div>
  if (isLoading) return <div>loading</div>
  return <div>{data.name}</div>
}

For TypeScript users, fallback and Suspense settings affect the inferred shape of data. The type tests show that when Suspense is represented in the options type, data can be treated as defined, while partial generic inference can still produce a wider type if the configuration type is not supplied. The tests also show that fallback data can be plain data or a promise-compatible response. When precise non-undefined data types matter, carry the relevant configuration type through the hook call rather than relying on partial inference.

Sources: src/_internal/types.ts, test/type/config.tsx

Next Steps

Use SWRConfig at application, layout, route, or feature boundaries where hooks should share a cache and defaults. Start with a global fetcher and callback policy, then add fallback or cache data only where server rendering or prefilled data is needed. If a subtree must isolate state, provide a different cache provider through configuration so mutations and subscriptions remain scoped. For more detail, continue with the pages on global configuration, cache providers, useSWR, mutation, Suspense and server rendering, and TypeScript types.