State

state/query-client-stable

The QueryClient is created once - in useState(() => new QueryClient()) or a module helper - never in a component's render.

seriousstaticfe-data-fetching

Why

const queryClient = new QueryClient() in a component body builds a new, empty cache on every render: every query refetches, loading spinners flash, and a refetch that re-renders the provider can loop. A client at module level is the opposite problem on a server: one cache shared by every request, leaking one user's data to the next.

Fix

In a component, create it once: const [queryClient] = useState(() => new QueryClient({ defaultOptions: { queries: { staleTime: 60_000 } } })). In a framework with server rendering, use a getQueryClient() helper that makes a new client per request on the server and reuses one in the browser. A plain client-only app may keep one module-level client.

Examples

// bad
export function Providers({ children }) {
  const queryClient = new QueryClient()
  return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}
// good
export function Providers({ children }) {
  const [queryClient] = useState(() => new QueryClient())
  return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}

Sources

Facts

Id
state/query-client-stable
Severity
serious
Check
static checked in the source by audit
Applies to
jsx
Only in projects with
tanstack-query
Taught by the skill
fe-data-fetching Data fetching
Since version
0.1.0

Rule file on GitHub

Read it in the terminal

npx github:dawidolko/frontend-skills explain state/query-client-stable