All Docs
FeaturesMaking Tax DigitalUpdated February 25, 2026

Cutting API Calls by Up to 80% with Smarter React Query Caching

Cutting API Calls by Up to 80% with Smarter React Query Caching

Version: 1.0.44
Category: Performance


The Problem

Prior to v1.0.44, the tRPC QueryClient was created with no configuration:

// Before — no defaultOptions
const queryClient = new QueryClient()

React Query's out-of-the-box staleTime is 0. This means every query is treated as stale the moment it resolves — so every time a user navigates back to a page, React Query immediately discards the cached data and fires a new network request.

In practice, returning to the dashboard triggered 5 or more API calls on every navigation, hitting endpoints that serve data that barely ever changes:

  • availableTaxYears — changes once a year at most
  • categoryMeta — static reference data
  • connectedAgents — changes only when the user explicitly connects or disconnects an agent

This made the application feel slower than necessary and placed avoidable load on the server.


The Fix

The QueryClient in src/lib/trpc/provider.tsx is now initialised with explicit caching defaults:

// After — sensible caching defaults
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 30_000,   // data is fresh for 30 seconds
      gcTime: 300_000,     // unused cache entries are kept for 5 minutes
    },
  },
})

What these values mean

OptionValueEffect
staleTime30 secondsCached data is considered fresh for 30 s after it was last fetched. Navigating back to a page within that window skips the network request entirely.
gcTime5 minutesInactive cache entries are held in memory for 5 minutes before being garbage-collected, so returning to a page after a short absence still benefits from the cached value.

Per-query overrides for stable data

For data that changes very infrequently, a longer staleTime of 1 hour is applied at the query level:

  • availableTaxYears — the set of HMRC tax years available for submission changes at most once a year.
  • categoryMeta — category definitions are static reference data and do not change between user sessions.

This means a user can navigate freely around the application for an entire session without these endpoints being hit more than once.


Impact

60–80% reduction in API calls during normal navigation.

This is the single most impactful frontend performance change in the codebase. The improvement is felt immediately — the dashboard loads faster on return visits, and the server handles significantly less traffic from routine page transitions.


Notes for Developers

  • The global staleTime: 30_000 default applies to all tRPC queries unless overridden.
  • To set a per-query staleTime when using tRPC + React Query, pass staleTime inside the query options:
trpc.availableTaxYears.useQuery(undefined, {
  staleTime: 60 * 60 * 1000, // 1 hour
})
  • gcTime (formerly cacheTime in React Query v4) controls how long inactive (unmounted) query data is kept in memory. It does not affect whether a query is considered stale — that is controlled solely by staleTime.
  • If a query must always reflect the latest server state (e.g. live submission status), you can opt out by setting staleTime: 0 on that specific query.