React Query: What Is `staleTime` and Why Should You Care?

Published: (February 26, 2026 at 05:10 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

What Does “Stale” Mean?

Think of it like milk in your fridge.

  • Fresh milk – you just bought it, you trust it, you drink it without thinking.
  • Stale milk – it’s been sitting there for a while; it might still be fine, but you’d probably want to check or get a new one.

React Query treats your fetched data the same way:

  • Fresh data – “I just got this, no need to fetch again.”
  • Stale data – “This might be outdated. I’ll refetch it when I get the chance.”

Important: Stale data is still shown to the user from the cache. React Query doesn’t show a loading spinner—it silently refetches in the background and updates the UI only if something changed.

The Default Behavior (staleTime = 0)

By default, staleTime is 0. That means the instant your data is cached, React Query marks it as stale.

So even if you fetched a list of books 1 second ago, React Query thinks: “This could be outdated, let me refetch it.”

When Does React Query Actually Refetch Stale Data?

Refetches only occur on specific triggers:

TriggerWhat happens
Window refocusYou switch to another tab, then come back
Component mountA component using this query mounts/remounts
Network reconnectYou go offline and come back online

Common Misconception

“Does moving my mouse trigger a refetch?”

Nope! Only switching away from the tab and coming back (window refocus) does. If you stay on the same tab for 30 minutes, no refetch happens until one of the triggers above occurs.

Setting staleTime: A Real Example

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5, // 5 minutes
    },
  },
});

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      {/* Your app components */}
    </QueryClientProvider>
  );
}

With this setup:

  • User visits the page → React Query fetches books from the API.
  • User switches tabs and returns 2 minutes later → Data is still fresh. No refetch; result comes instantly from cache.
  • User returns 7 minutes later → Data is now stale. React Query refetches in the background, and the UI updates if new data is available.

staleTime vs cacheTime (gcTime) — Don’t Mix Them Up!

staleTimegcTime (formerly cacheTime)
What it controlsHow long data is considered freshHow long unused cached data stays in memory
Default0 (immediately stale)5 minutes
After it expiresData is marked stale; refetched on next triggerData is garbage‑collected (removed from cache)

Think of it this way:

  • staleTime = “How long should I trust this data?”
  • gcTime = “How long should I keep this data in memory after no component is using it?”

Quick Visual Timeline

Fetch happens at 0:00
|
|-- 0:00 to 5:00  → Data is FRESH (no refetch, served from cache)
|-- 5:00+         → Data is STALE (refetch on next trigger)
|
|-- If no component uses this data for 5 min → cache is GARBAGE COLLECTED

Per-Query staleTime

You can also set staleTime on individual queries instead of globally:

// This specific query stays fresh for 10 minutes
const { data } = useQuery({
  queryKey: ["books", id],
  queryFn: () => fetchBook(id),
  staleTime: 1000 * 60 * 10, // 10 minutes
});

This overrides the global default for just this one query.

TL;DR

  • staleTime = 0 (default): data is immediately stale, refetched on every trigger.
  • staleTime = 1000 * 60 * 5: data is fresh for 5 minutes, avoiding unnecessary API calls during that period.
  • Stale data is still displayed from cache — refetch happens silently in the background.
  • Refetch triggers: window refocus, component mount, network reconnectnot mouse movement.
  • staleTime (freshness) and gcTime (cache lifetime) are distinct concepts.

Happy coding!

0 views
Back to Blog

Related posts

Read more »