skip to content

In a React Native app using TanStack Query v5, when would you set networkMode to 'offlineFirst' or 'always' instead of the default 'online'?

level: seniorimportance: nice to knowfreq 20%

answer

  1. default 'online' gates on onlineManager
  2. 'offlineFirst' tries once, then pauses retries
  3. 'always' ignores connectivity entirely
  4. refetchOnReconnect defaults false under 'always'
  5. per-query persister implies 'offlineFirst'

basics

~20 s

Keep 'online' for network queries. Use 'offlineFirst' when the queryFn might answer offline: it runs once and only pauses retries. Use 'always' when the queryFn never touches the network, such as an on-device storage read.

solid answer

~40 s

`networkMode` decides how a query treats `onlineManager`, which in React Native is only as good as its NetInfo wiring. Under the default `'online'`, a query does not run its `queryFn` while offline: it sits at `fetchStatus: 'paused'` and resumes on reconnect. Under `'offlineFirst'`, the `queryFn` runs once regardless; if that attempt fails, retries pause until the device is online. That fits a `queryFn` that can succeed without a connection, for example one that reads a local copy first or goes through a caching layer. Under `'always'`, connectivity is ignored: nothing pauses, retries run and the query can end in `error`, and `refetchOnReconnect` defaults to `false`. That fits a `queryFn` that reads MMKV, SQLite or a computed value. The mode can be set per query or in `defaultOptions`, and mutations have the same option.

code

typescript · 14 lines
typescript
import { QueryClient, useQuery } from '@tanstack/react-query';

export const queryClient = new QueryClient({
  defaultOptions: { queries: { networkMode: 'online' } },
});

// Reads a locally computed watchlist: no network involved, never pause it.
export function useWatchlistSymbols(readLocal: () => Promise<string[]>) {
  return useQuery({
    queryKey: ['watchlist', 'symbols'],
    queryFn: readLocal,
    networkMode: 'always',
  });
}

go deeper

for a junior

Recall the three values and that 'online' is the default, pausing network queries while the device is offline.

for a middle

Explain the start and continue checks, and what paused, errored and resumed look like under each mode.

for a senior

Match each queryFn to a mode by where its data comes from, and know that a per-query persister and an untrusted connectivity signal both push towards 'offlineFirst'.

for a principal

Decide how the app behaves when the connectivity signal is wrong, and whether modes are a per-team default or a per-query decision reviewed in code.

## What networkMode controls Every TanStack Query query has a **`networkMode`**: `'online'` (the default), `'offlineFirst'` or `'always'`. It answers one question: *does connectivity, as reported by `onlineManager`, gate this query?* On React Native that manager only knows what the app tells it through NetInfo, so the mode is really a statement about how much you trust that signal and whether the `queryFn` needs the network at all. Two checks inside the retryer make the difference: - **Can it start?** Under `'online'` the first attempt starts only if `onlineManager.isOnline()` is true; under the other two modes it always starts. - **Can it continue?** After a failed attempt and its retry delay, a retry only proceeds if the app is focused and, unless the mode is `'always'`, online. Otherwise it pauses. ## The three modes side by side | | `'online'` (default) | `'offlineFirst'` | `'always'` | |---|---|---|---| | First attempt while offline | paused, not run | runs | runs | | Retries while offline | paused | paused | run, then `error` | | `fetchStatus: 'paused'` possible | yes | yes, after a failed first attempt | no connectivity pause | | `refetchOnReconnect` default | `true` | `true` | `false` | | Fits | plain network requests | a `queryFn` that may answer offline | a `queryFn` that never uses the network | ## When 'offlineFirst' earns its place The TanStack Query docs describe `'offlineFirst'` for a first request that can succeed from a cache, their example being a service worker or HTTP caching on the web. React Native has no service worker, so on a phone the fitting cases are: - a `queryFn` that reads the last saved portfolio from on-device storage and only then goes to the network; - a request routed through a layer you control that can answer from a local copy; - a connectivity signal you do not fully trust: if NetInfo reports disconnected while a request would succeed, `'online'` never tries, whereas `'offlineFirst'` makes one real attempt and pauses only if it fails. It is also the mode TanStack Query picks by itself when a query is given the per-query `persister` option (built with `experimental_createQueryPersister`) and no mode is set, because such a query can be served from storage. ## When 'always' is right Choose `'always'` when the `queryFn` is not a network call: - a read from MMKV, AsyncStorage, expo-sqlite or the file system; - a value computed on the device, such as a derived chart series. Pausing those while offline would be wrong, since they cannot be blocked by a missing connection, and refetching them on reconnect is pointless, which is why `refetchOnReconnect` defaults to `false` in this mode. Turn it back on only if the local source is itself refreshed by a network sync. ## Choosing, in order 1. Does the `queryFn` touch the network? If never, `'always'`. 2. Can it succeed offline some of the time? If yes, `'offlineFirst'`. 3. Otherwise keep `'online'`, and make sure the UI handles `isPaused` on a first load. Set a default in `new QueryClient({ defaultOptions: { queries: { networkMode } } })` and override per query where a screen differs. Remember that focus still gates retries in every mode: a query wired to `AppState` pauses its retries in the background even under `'always'`. ## What networkMode does not do - It does not store anything: persisting the cache across launches is a separate plugin. - It does not queue writes; mutations accept the same option, but how paused writes are stored and replayed is a separate design. - It does not detect connectivity; it only reads what `onlineManager` has been told.

  • Why does refetchOnReconnect default to false when networkMode is 'always'?
    Under `'always'` the query is declared independent of connectivity, so a reconnect says nothing about whether its data changed. TanStack Query sets `refetchOnReconnect` to `networkMode !== 'always'` when you leave it undefined. You can still set it to `true` if the local data is refreshed by a network sync.
  • Under 'offlineFirst', what does the user see if the device is offline and the first attempt fails?
    The `queryFn` runs once and fails; instead of retrying immediately, the retryer pauses because the device is offline, and `fetchStatus` becomes `paused` with the query keeping its current status. It continues the remaining retries when `onlineManager` reports online, as an `'online'` query would.

saying these in an interview costs you the question

  • 'offlineFirst' makes TanStack Query save the cache to disk automatically
  • 'always' still pauses queries while NetInfo reports the device offline
  • networkMode can only be set once, on the QueryClient
  • Under 'online' an offline query fails immediately with a network error
  • 'offlineFirst' means the queryFn never runs while offline