Skip to main content
Caching is at the heart of TanStack Query. It implements a stale-while-revalidate caching strategy that provides a great user experience while keeping data fresh.

The Query Cache

The QueryCache is responsible for storing and managing all query data. From queryCache.ts:92-98:
The cache is a Map where:
  • Keys are query hashes (derived from query keys)
  • Values are Query instances containing state and data

Cache Time vs Stale Time

Two fundamental timing concepts control caching behavior:

Stale Time

Stale time determines how long data is considered fresh:
  • Default: 0 (data is immediately stale)
  • Purpose: Controls when background refetches occur
  • Type: number | 'static'
From types.ts:102-111:
Setting staleTime: 'static' means the data is never considered stale and won’t automatically refetch.

GC Time (Garbage Collection Time)

GC time determines how long inactive data stays in the cache:
  • Default: 5 minutes (300,000 ms)
  • Purpose: Controls when unused data is garbage collected
  • Renamed from: cacheTime in v4
From types.ts:242-246:

The Relationship

Timeline:
  • 0s - Query executes, data is fresh
  • 1m - Data becomes stale (will refetch on next mount/focus)
  • 5m - If no observers, data is garbage collected
gcTime should always be greater than or equal to staleTime. Otherwise, data might be removed from the cache while it’s still fresh.

Stale-While-Revalidate Strategy

TanStack Query implements a stale-while-revalidate pattern:
  1. Serve stale data immediately from cache
  2. Revalidate in the background if data is stale
  3. Update UI when fresh data arrives
First render:
  • No cached data → shows loading state
  • Fetches data → shows posts
Second render (within 1 minute):
  • Shows cached posts immediately (stale time not exceeded)
  • No background fetch
Third render (after 1 minute):
  • Shows cached posts immediately
  • Fetches in background (isFetching: true)
  • Updates when new data arrives

Cache Lifecycle

1. Query Creation

When a query is first used, it’s built in the cache. From queryCache.ts:100-131:

2. Observer Subscription

When components use the query, observers are added. From query.ts:343-351:

3. Observer Removal

When components unmount, observers are removed. From query.ts:354-374:

4. Garbage Collection

When a query has no observers, it’s scheduled for garbage collection based on gcTime. From the Removable class (parent of Query):

Cache Manipulation

Reading Cache Data

Get data from the cache imperatively:
From queryClient.ts:129-138:

Setting Cache Data

Manually update cache data:
From queryClient.ts:176-209:

Removing Cache Data

Remove queries from the cache:
From queryClient.ts:247-256:

Cache Persistence

Persist cache to storage for offline support:
From the basic example (examples/react/basic/src/index.tsx:8-18):

Structural Sharing

TanStack Query performs structural sharing to preserve referential equality:
From types.ts:261-267:
Structural sharing is especially useful for large lists where only a few items change. It preserves references to unchanged objects.

Cache Configuration

Global Defaults

Per-Query Configuration

Query-Specific Defaults

Set defaults for specific query keys:

Cache Events

Listen to cache events:
From queryCache.ts:19-30:

Best Practices

1. Set Appropriate Stale Times

2. Use Longer GC Times for Expensive Queries

3. Prefetch for Better UX