Global Fetcher

Purpose and Scope

This page explains the Global Fetcher example pattern: put a shared fetcher in SWRConfig so components can call useSWR with only a key. In the README quick start, useSWR receives both a key and a fetcher in each component. That is the most explicit form and is useful for learning the hook contract, but applications often have one default transport convention, such as calling fetch(url).then(res => res.json()) for JSON API routes. A global fetcher moves that convention to the provider boundary and leaves individual components focused on the resource key and UI states. Sources: README.md

SWR itself is described as a React Hooks library for data fetching, where the hook returns cached data first, revalidates, and then updates the component with fresh data. A global fetcher does not change that stale-while-revalidate model. It only changes where the asynchronous request function is supplied. Components still choose keys, receive data, error, and loading state, and rerender as SWR updates the cache. The benefit is consistency: the same request behavior can be shared across a page, layout, app shell, or test fixture without repeating it at every hook call. Sources: README.md

The official Global Fetcher example is intentionally small: its idea is to use the SWRConfig provider to set up the fetcher globally instead of passing a fetcher per hook. Read this page as the practical recipe behind that sentence. It is most appropriate when most hooks in a subtree use the same fetch convention. If a component needs a different transport, authentication mode, response parser, or mock implementation, it can still pass an explicit fetcher at that call site and keep the exception local.

Relevant Source Files

  • README.md - Defines SWR as a React Hooks data-fetching library, shows the ordinary per-hook useSWR('/api/user', fetcher) form, and explains the key, fetcher, and returned data, isLoading, and error values.
  • e2e/site/app/render-suspense-fetcher/page.tsx - Demonstrates that a fetcher is the asynchronous function SWR invokes for a key, including a Suspense render path where changing the key and fetcher result changes the displayed data.
  • e2e/site/README.md - Documents how to run the E2E Next.js site locally with npm run dev, yarn dev, or pnpm dev, which is useful when validating example behavior in an app environment.
  • src/_internal/utils/global-state.ts - Shows that SWR associates global runtime state with a cache through SWRGlobalState, a WeakMap<Cache, GlobalState> used for request deduplication and listeners.

Core Primitives

The two primitives to understand are the key and the fetcher. The README defines the key as the unique identifier of a request, normally the URL of the API. The fetcher accepts that key and returns data asynchronously. When you configure a global fetcher, you are not making the key global; every hook still provides its own key so SWR can identify a cache entry and know what to revalidate. The global part is only the default implementation used to turn a key into a promise of data. Sources: README.md

The returned hook state remains the same with or without a global fetcher. The README shows data, error, and isLoading: before the fetcher finishes, data is undefined and loading is true; when the response resolves, SWR sets data or error and rerenders the component. In a global fetcher setup, components keep the same state handling, but their hook calls are shorter. This makes it easier to scan a component tree because each useSWR call highlights the resource being requested instead of repeating boilerplate network code. Sources: README.md

SWR also has global runtime coordination around cache instances. The internal SWRGlobalState is a weak map from a cache provider to the global state used to deduplicate requests and store listeners. That implementation detail matters for this example because provider-level configuration is not just syntactic convenience: SWR organizes shared behavior around the cache and configuration boundary. When multiple hooks live under the same provider and cache, SWR can coordinate updates and listeners for those hooks as part of the same runtime scope. Sources: src/_internal/utils/global-state.ts

Example Flow

Start from the explicit form in the README: pass both a key and a fetcher to useSWR. Then lift the fetcher into an app-level provider. The component no longer needs to import or define the default request function; it only names the resource key. This is the core refactor the Global Fetcher example is meant to demonstrate, and it is especially useful in Next.js examples where many pages call API routes with the same JSON parsing behavior.

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

The important sequencing is that the provider wraps the components that rely on the default fetcher. Inside that boundary, Profile calls useSWR('/api/user'), and SWR can use the configured fetcher to resolve the key. If Profile were rendered outside the provider, it would need an explicit fetcher again unless another configuration boundary supplied one. This keeps configuration placement visible and intentional: put the provider near the part of the tree that shares the same request conventions, not necessarily at the absolute root of every application.

Runtime Behavior and Suspense

The E2E Suspense page is not the global-fetcher example, but it is a useful runtime signal for what a fetcher does. The page keeps a fetcher function in a ref, calls useSWR with a key derived from local state, and enables { suspense: true }. Buttons update the fetcher result and key prefix, causing the rendered data to switch between foo and bar through SWR's asynchronous path. This confirms that the fetcher remains the function responsible for producing data for a given key, even when rendering is coordinated through React Suspense. Sources: e2e/site/app/render-suspense-fetcher/page.tsx

When combining a global fetcher with Suspense, the same rule applies: the provider supplies the default asynchronous data function, and the hook options determine the render behavior. A component can call useSWR(key, { suspense: true }) in projects that use the appropriate SWR API shape, or pass options in the supported position for its version. The fetcher may be global, but Suspense fallback handling still belongs to React. The E2E page wraps the SWR-using section in <Suspense fallback={<div data-testid='fallback'>loading</div>}>, making the fallback boundary explicit. Sources: e2e/site/app/render-suspense-fetcher/page.tsx

Running and Validating the Example

The official example instructions follow the same pattern used by the repository examples: download the example directory, install dependencies, and run the development server. For local app validation in this repository, the E2E site README documents the standard Next.js development commands: npm run dev, yarn dev, or pnpm dev, then open the local site in a browser. That workflow is useful when you want to verify that a provider-level fetcher is applied to the components beneath it and that loading, error, and data states still behave as expected. Sources: e2e/site/README.md

A practical validation checklist is short. First, render a component under SWRConfig with a global fetcher and call useSWR with only a key. Second, confirm the UI enters the loading state before the response resolves and then displays the returned data. Third, add a second component using another key and verify it does not need to repeat the fetcher. Finally, pass a local fetcher to one hook if you need an exception; that component should be readable as a deliberate override rather than part of the default path.

System-to-Code Mapping

ConcernSource-backed signalHow it applies to the global fetcher pattern
Hook contractREADME.md shows useSWR('/api/user', fetcher) and explains key, fetcher, data, loading, and errorThe global pattern removes repeated fetcher arguments while preserving the same key and return-state contract
Fetcher runtime rolee2e/site/app/render-suspense-fetcher/page.tsx invokes a promise-returning fetcher and displays resolved dataA global fetcher is still the asynchronous function SWR calls to produce data for a key
Shared SWR scopesrc/_internal/utils/global-state.ts stores global state per cache in a weak mapProvider and cache boundaries are meaningful because SWR coordinates listeners and deduplication per cache
Local verificatione2e/site/README.md lists development-server commandsUse the app workflow to observe provider-level configuration in a browser

Next Steps

Use a global fetcher when your application has a default request style, then keep exceptions explicit at the hook call site. Continue with SWRConfig for the complete configuration surface, useSWR for the primary hook reference, and the revalidation pages for how focus, reconnect, polling, and manual mutation interact with cached data after the fetcher has resolved.