Files
dotfiles/dot_agents/skills/tanstack-query-best-practices/rules/cache-gc-time.md
T
Prad Nukala 6406208b35 shell: fish functions -> ~/.local/bin executables + bash/zsh ports; manage ~/.agents
- 16 cross-shell utilities converted to sh/bash chezmoi executables:
  ai c2p cp-appid extract_agents fab gdc gh-sonr-org-migrate ghg-clone
  ghn gho git-summary launch_omp_livediff_overlay lc-elir mdcp mdp pj
  (ghg-clone not named ghg: unrelated cargo binary owns that name)
- cwd/history helpers stay per-shell: yy c cd clip-last + ghg/ghn/gho
  cd-wrappers in bash/functions/ and zsh/functions/, loaded by rc files
- fish keeps only shell-state functions; converted ones now hit PATH
- cp-appid ignore gating moved to .local/bin path
- dot_agents/skills: 82 skills materialized from dotstate storage so
  dot_claude skill symlinks resolve on fresh bootstrap; dotstate
  profile/symlinks.json released .agents/skills .bashrc .zshrc
2026-08-10 15:15:06 -04:00

2.8 KiB

cache-gc-time: Configure gcTime for Inactive Query Retention

Priority: CRITICAL

Explanation

gcTime (garbage collection time, formerly cacheTime) controls how long inactive queries remain in the cache before being garbage collected. Default is 5 minutes. Configure based on your navigation patterns and memory constraints.

Bad Example

// Not considering gcTime for frequently revisited pages
const { data } = useQuery({
  queryKey: ['dashboard-stats'],
  queryFn: fetchDashboardStats,
  // Default gcTime of 5 minutes - might be too short for frequently revisited data
})

// Setting gcTime too high without consideration
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      gcTime: Infinity,  // Never garbage collect - potential memory leak
    },
  },
})

// Setting gcTime to 0 - cache is immediately removed
const { data } = useQuery({
  queryKey: ['user-data'],
  queryFn: fetchUserData,
  gcTime: 0,  // Loses cache benefits entirely
})

Good Example

// Longer gcTime for frequently revisited data
const { data } = useQuery({
  queryKey: ['dashboard-stats'],
  queryFn: fetchDashboardStats,
  gcTime: 30 * 60 * 1000,  // 30 minutes - user returns to dashboard often
})

// Shorter gcTime for rarely revisited large data
const { data: report } = useQuery({
  queryKey: ['detailed-report', reportId],
  queryFn: () => fetchReport(reportId),
  gcTime: 2 * 60 * 1000,  // 2 minutes - large payload, viewed once
})

// Sensible default with query-specific overrides
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      gcTime: 10 * 60 * 1000,  // 10 minutes default
    },
  },
})

Understanding gcTime vs staleTime

Query Mount → Data Fresh (staleTime) → Data Stale → Query Unmount → gcTime countdown → Garbage Collected

Timeline example (staleTime: 1min, gcTime: 5min):
0:00 - Query mounts, fetches data
0:00-1:00 - Data is fresh (no background refetch)
1:00+ - Data is stale (background refetch on new mount)
5:00 - User navigates away, query unmounts
5:00-10:00 - Data in cache but inactive (gcTime countdown)
10:00 - Data garbage collected (next mount = full loading state)
Scenario gcTime Rationale
Frequently revisited routes 15 - 30min Instant navigation
Detail pages (viewed once) 2 - 5min Memory efficient
Large payloads 1 - 2min Prevent memory bloat
Critical user data 30min+ Offline-like experience
SSR hydration >= 2s Prevent hydration issues

Context

  • gcTime countdown starts when ALL query observers unmount
  • Remounting before gcTime expires returns cached data instantly
  • Setting gcTime < staleTime is rarely useful
  • For SSR, avoid gcTime: 0 (use minimum 2000ms to allow hydration)
  • Monitor memory usage in long-running applications