TanStack Query cache invalidation lifecycle diagram fresh stale inactive

Cache Invalidation, Refetching Strategies & Stale Times

TanStack Query Cache Invalidation: staleTime, gcTime, and invalidateQueries Explained

TanStack Query cache invalidation is the mechanism that keeps your cached data honest after something changes on the server. In our previous post, we introduced TanStack Query and saw how useQuery simplifies server state management — handling loading states, errors, and basic caching automatically.

The real power of TanStack Query shows up once you ask a harder question: when is cached data still fresh, when does it go stale, and when should TanStack Query cache invalidation kick in to force a refetch? In this post, we dive into TanStack Query’s cache lifecycle, the difference between staleTime and gcTime, invalidation with queryClient.invalidateQueries(), and background refetching strategies.

Also Read: Declarative Data Fetching with TanStack Query

The Query Lifecycle: Fresh vs. Stale vs. Inactive

Every query moves through a predictable state machine:

  • Fetching → Fresh, once data arrives. No background refetching required.
  • Fresh → Stale, after staleTime expires. Data is still usable but ready to refetch.
  • Stale → Inactive, once a query has zero subscribers. Stays in memory until gcTime expires.
  • Inactive → Garbage Collected, when gcTime runs out.
TanStack Query cache invalidation staleTime gcTime timeline diagram
Cache Invalidation, Refetching Strategies & Stale Times 7

Fresh data was fetched recently and is considered fully up to date. As long as a query is Fresh, TanStack Query won’t trigger network requests on component remounts or window refocuses — there’s simply nothing for cache invalidation to do yet.

Stale data has passed its staleTime threshold. It still renders on screen immediately, so the user sees zero spinners, but TanStack Query silently triggers a background re-fetch on the next trigger event, like a window focus or route change. This is exactly the gap TanStack Query cache invalidation is designed to close on demand, rather than waiting for a passive trigger.

Inactive queries have no components currently rendering them — for example, after the user navigates away. Once a query stays Inactive longer than gcTime, it’s garbage collected to prevent memory leaks.

staleTime vs. gcTime: A Crucial Distinction

Two parameters govern how long data lives in memory, and beginners often mix them up.

ParameterDefaultControls
staleTime0 msHow long fetched data is treated as fresh before it’s marked stale
gcTime (formerly cacheTime)5 minutesHow long inactive query data stays in memory before deletion

Why does TanStack Query default staleTime to 0? By default, data is marked stale immediately. The user sees cached data instantly on route navigation — the stale-while-revalidate pattern — while TanStack Query triggers a background refetch to confirm nothing changed server-side.

If you’re querying data that rarely changes — country lists, user preferences, product categories — set a higher staleTime to cut unnecessary server load:

js

const { data: categories } = useQuery({
  queryKey: ['categories'],
  queryFn: fetchCategories,
  staleTime: 1000 * 60 * 60, // treat as fresh for 1 hour
  gcTime: 1000 * 60 * 60 * 24, // keep inactive cache for 24 hours
});

How TanStack Query Cache Invalidation Works

Automatic revalidation handles passive background updates. But data mutations — creating a blog post, updating a profile — need active TanStack Query cache invalidation. Instead of manually rewriting cache structures by hand, you mark affected query keys as stale with queryClient.invalidateQueries(). TanStack Query then automatically refetches any active component using those keys.

jsx

import { useQueryClient } from '@tanstack/react-query';

function CreatePostButton() {
  const queryClient = useQueryClient();

  const handleCreatePost = async () => {
    await apiCreatePost({ title: 'New Post' });

    // Triggers TanStack Query cache invalidation for the 'posts' key
    queryClient.invalidateQueries({ queryKey: ['posts'] });
  };

  return <button onClick={handleCreatePost}>Create Post</button>;
}

Also Read: Reverse Proxies & Edge Security Nginx vs. Caddy vs. Pingora (Rust) Explained

TanStack Query cache invalidation triggered by a mutation diagram
Cache Invalidation, Refetching Strategies & Stale Times 8

Exact Matching vs. Fuzzy Matching in Cache Invalidation

This hierarchical matching is what makes TanStack Query cache invalidation so flexible — you can target one specific query or an entire family of related queries with a single call. Query keys are matched hierarchically by default:

js

// Invalidates ['posts'], ['posts', 1], and ['posts', { status: 'draft' }]
queryClient.invalidateQueries({ queryKey: ['posts'] });

// Invalidates ONLY the exact key ['posts']
queryClient.invalidateQueries({
  queryKey: ['posts'],
  exact: true,
});

Fine-Tuning Refetching Behavior

TanStack Query gives you granular control over when background refetches fire. Configure these globally in QueryClient or per query hook:

TanStack Query cache invalidation refetch trigger icons diagram
Cache Invalidation, Refetching Strategies & Stale Times 9

jsx

const { data } = useQuery({
  queryKey: ['dashboard-stats'],
  queryFn: fetchStats,
  refetchOnWindowFocus: true, // refetch when the tab regains focus
  refetchOnMount: true,       // refetch on remount if stale
  refetchOnReconnect: true,   // refetch after the network reconnects
  refetchInterval: 10000,     // poll every 10 seconds
});

Summary Checklist

  • staleTime controls when data is considered stale and eligible for a background refetch.
  • gcTime controls when unused cache data is deleted from memory.
  • TanStack Query cache invalidation via invalidateQueries() is the primary way to mark data stale after a mutation.
  • Deduplication and revalidation together mean TanStack Query loads instantly from cache while keeping server state in sync.

Conclusion

Understanding staleTime, gcTime, and TanStack Query cache invalidation turns asynchronous data fetching from an unpredictable headache into a deterministic, well-optimized pipeline. In our next post, we’ll cover optimistic UI updates and infinite scroll pagination using useMutation and useInfiniteQuery.

Content Protection by DMCA.com
Spread the love
Scroll to Top
×