Background Refetching

Purpose and Scope

Background refetching is the part of TanStack Query that keeps server state synchronized after the first successful render. A query can be done with its initial hard-loading state and still be fetching again because the data is stale, the browser regained focus, an interval elapsed, or a mutation invalidated related data. The React guide distinguishes these cases by showing status === 'pending' for the initial loading branch and isFetching for any active fetch, including background work. That distinction lets an interface keep useful cached data visible while still communicating that a refresh is happening.

Sources: docs/framework/react/guides/background-fetching-indicators.md

This page covers the user-facing patterns that are explicitly documented for React and Angular: per-query fetching indicators, global fetching indicators, refetching stale data when focus returns, custom focus events, and interval-based auto refetching. The same product behavior is useful across adapters, but the public APIs are framework-native. React examples use hooks such as useQuery, useIsFetching, useMutation, and useQueryClient; Angular examples use injection functions such as injectQuery and injectIsFetching, plus provideTanStackQuery for application-level defaults.

Sources: docs/framework/react/guides/background-fetching-indicators.md, docs/framework/angular/guides/background-fetching-indicators.md, docs/framework/react/guides/window-focus-refetching.md, docs/framework/angular/guides/window-focus-refetching.md

Relevant Source Files

  • docs/framework/react/guides/background-fetching-indicators.md - Defines the React-facing difference between status and isFetching, and shows useIsFetching for a global indicator.
  • docs/framework/react/guides/window-focus-refetching.md - Documents default focus refetching, refetchOnWindowFocus, focusManager.setEventListener, React Native AppState, and manual focus overrides.
  • docs/framework/angular/guides/background-fetching-indicators.md - Provides Angular signal-style examples for per-query isFetching() and global injectIsFetching().
  • docs/framework/angular/guides/window-focus-refetching.md - Shows Angular configuration for disabling focus refetching globally through provideTanStackQuery and per query through injectQuery.
  • examples/react/auto-refetching/src/pages/index.tsx - Demonstrates a running React workflow with refetchInterval, a visual fetching dot, mutation-driven invalidation, and devtools.

Core Primitives

A query result exposes two related but different signals. status describes the resolved lifecycle for the current query result, so the docs use it to decide whether to render the initial loading state, an error, or the successful data view. isFetching describes transport activity and can be true while successful data is already available. In practice, that means the UI can render cached todos and place a smaller “Refreshing...” affordance nearby instead of blanking out the list on every revalidation.

Sources: docs/framework/react/guides/background-fetching-indicators.md, docs/framework/angular/guides/background-fetching-indicators.md

Global fetching state is the aggregate version of the same idea. React exposes it through useIsFetching, while Angular exposes injectIsFetching. Both examples render an application-level message only when at least one query is fetching, including background refetches. This is useful for top bars, route shells, or status areas where the user should know that the application is synchronizing but should not be blocked from reading existing data. Treat this as a non-modal signal; it complements, rather than replaces, per-query pending and error branches.

Sources: docs/framework/react/guides/background-fetching-indicators.md, docs/framework/angular/guides/background-fetching-indicators.md

import { useIsFetching } from '@tanstack/react-query'
 
function GlobalLoadingIndicator() {
  const isFetching = useIsFetching()
 
  return isFetching ? (
    <div>Queries are fetching in the background...</div>
  ) : null
}

Window Focus Refetching

TanStack Query automatically requests fresh data in the background when a user leaves the application and returns, as long as the query data is stale. The React guide calls this “Window Focus Refetching” and documents refetchOnWindowFocus as the switch for disabling it. The option can be set globally on QueryClient defaults or locally on a single useQuery call. The Angular guide mirrors the same option through provideTanStackQuery for app configuration and injectQuery for a single query.

Sources: docs/framework/react/guides/window-focus-refetching.md, docs/framework/angular/guides/window-focus-refetching.md

Use the global setting when focus refetching is not appropriate for an application class, such as an environment with expensive queries or a workflow where returning to the tab should never trigger network work automatically. Use the per-query setting when most data should revalidate on focus but a particular resource should not. The default shown in the docs is true, so disabling it should be an intentional UX decision rather than a workaround for normal background fetching indicators.

Sources: docs/framework/react/guides/window-focus-refetching.md, docs/framework/angular/guides/window-focus-refetching.md

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      refetchOnWindowFocus: false, // default: true
    },
  },
})
 
useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  refetchOnWindowFocus: false,
})

Custom Focus Management

The focus system is configurable through focusManager. The React guide explains that focusManager.setEventListener receives a callback that should be fired when the window is focused, removes the previously registered handler, and installs the new handler. The documented default listens for visibilitychange, checks whether document.visibilityState === 'visible', and returns an unsubscribe function that removes the event listener. This contract matters because custom event sources must clean up correctly when a new handler replaces them.

Sources: docs/framework/react/guides/window-focus-refetching.md

React Native is handled differently because focus information comes from AppState, not from browser window events. The guide shows an AppState change handler that calls focusManager.setFocused(status === 'active') when the platform is not web, then removes the subscription from the effect cleanup. The same guide also documents focusManager.setFocused(true) to override the default focus state and focusManager.setFocused(undefined) to fall back to the default focus check. These escape hatches are for integration code, not ordinary query components.

Sources: docs/framework/react/guides/window-focus-refetching.md

import { AppState } from 'react-native'
import { focusManager } from '@tanstack/react-query'
 
function onAppStateChange(status: AppStateStatus) {
  if (Platform.OS !== 'web') {
    focusManager.setFocused(status === 'active')
  }
}

Auto Refetching Example Flow

The React auto-refetching example shows the same concepts in a concrete application. It creates a QueryClient, wraps the app in QueryClientProvider, and fetches /api/data with a useQuery keyed as ['todos']. The query sets refetchInterval to intervalMs, a piece of React state initialized to 1000. A numeric input updates that interval, which means the user can tune how often the query refetches without changing the query identity or leaving the page.

Sources: examples/react/auto-refetching/src/pages/index.tsx

The example renders Loading... only while status === 'pending' and renders an error message only while status === 'error'. Once data is available, it keeps the todo list visible and shows fetching activity with a small inline dot whose background becomes green when isFetching is true. That is a compact but important UX pattern: interval refetching can be frequent, so a full-page spinner would be noisy, while a lightweight indicator confirms that polling is active.

Sources: examples/react/auto-refetching/src/pages/index.tsx

Mutations in the same example demonstrate how background refetching combines with invalidation. addMutation posts to /api/data?add=${add} and clearMutation posts to /api/data?clear=1; both call queryClient.invalidateQueries({ queryKey: ['todos'] }) on success. Invalidation tells TanStack Query that the cached todos are no longer authoritative, so the list can be refreshed through the same query pipeline. The example also opens ReactQueryDevtools, which is useful while observing interval fetches, invalidations, and cache state changes.

Sources: examples/react/auto-refetching/src/pages/index.tsx

API and Option Reference

ConcernReact APIAngular APISource-backed behavior
Per-query background indicatorisFetching from useQuerytodosQuery.isFetching() from injectQueryTrue when the query is fetching, even after successful data exists.
Global background indicatoruseIsFetching()injectIsFetching()Counts whether any query is fetching, including background fetches.
Focus refetch defaultrefetchOnWindowFocus: true by defaultSame option through Angular query optionsStale data is refreshed when the user returns to the app.
Disable focus refetch globallynew QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false }}})provideTanStackQuery(new QueryClient(...))Applies the default option across queries using that client.
Disable focus refetch per queryuseQuery({ refetchOnWindowFocus: false })injectQuery(() => ({ refetchOnWindowFocus: false }))Applies only to the query being configured.
Custom focus sourcefocusManager.setEventListener and focusManager.setFocusedSame core focus manager package concept through adapter imports where availableReplaces the default event listener or manually overrides focus state.
Interval pollingrefetchIntervalAdapter query option when supported by query optionsRefetches on a timer while preserving the cached result view.

Implementation Guidance and Next Steps

When designing background refetching UX, start by separating hard loading from synchronization. The hard-loading branch should answer “do we have anything useful to show?”; the fetching indicator should answer “are we currently checking for fresher data?” For detail pages and lists, keep stable content on screen while showing a small refreshing label, badge, or progress affordance. For an application shell, use useIsFetching or injectIsFetching when the user needs global feedback that some server state is updating.

Sources: docs/framework/react/guides/background-fetching-indicators.md, docs/framework/angular/guides/background-fetching-indicators.md

Next, decide which refetch triggers are appropriate for the product. Focus refetching is on by default and is a good baseline for stale data, but it can be disabled globally or per query. Interval refetching is more explicit and should usually be paired with a subtle indicator like the example’s green dot. Mutation invalidation is event-driven and is often the right companion to forms or buttons that change server state. Read the query, mutation, invalidation, and devtools pages next to connect these indicators to cache lifecycle and debugging workflows.

Sources: docs/framework/react/guides/window-focus-refetching.md, docs/framework/angular/guides/window-focus-refetching.md, examples/react/auto-refetching/src/pages/index.tsx