What is Stale UI?
Stale UI occurs when the visual representation of data does not reflect the latest state of the backend or source of truth. The UI appears to be “frozen” on an older value even though the server has returned fresh data.
Why does caching lead to stale UI?
Caching stores a copy of a response so that subsequent requests can be served faster. If a cache is not invalidated or configured correctly, the stored copy is served instead of the fresh response, causing the UI to display outdated information.
- Improves performance and reduces load.
- Introduces a risk of serving old data when the cache lifetime exceeds the data‑change frequency.
- Multiple independent cache layers can exist simultaneously, making the source of staleness hard to pinpoint.
Common Caching Layers that Cause Stale UI
1. React Query (TanStack Query) Cache
What: In‑memory cache that stores query results keyed by a developer‑defined query key.
How: When a component mounts, React Query returns the cached data immediately and decides whether to refetch based on staleTime and refetch options.
Why it becomes stale:
- Mutation succeeds but the related query key is not invalidated.
- Wrong query key is invalidated, leaving the UI reading from an unchanged cache entry.
- Duplicated local React state that diverges from the query result.
2. Next.js fetch() Caching
What: Server‑side data cache (Data Cache) and full‑route cache used by the App Router.
How: Next.js may reuse a previously fetched API response or a pre‑rendered page instead of issuing a new request.
Why it becomes stale:
- Default cache‑control settings keep the response for a set period.
- Revalidation timers have not yet expired.
- Server actions or API routes update data but do not purge the saved copy.
3. Browser HTTP Cache
What: The browser stores copies of HTTP responses in memory or on disk.
How: Subsequent requests may be satisfied from the cache based on Cache‑Control, ETag, or Expires headers.
Why it becomes stale:
- Headers allow a long max‑age, so the browser never re‑requests the resource.
- Conditional requests return
304 Not Modifiedeven though the server data changed.
4. CDN / Edge Cache
What: An intermediary cache (e.g., Vercel, Cloudflare) that stores responses at edge locations.
How: Requests are intercepted by the CDN; if a cached copy exists and is still fresh, it is returned without hitting the origin server.
Why it becomes stale:
- Cache‑control headers permit a long TTL.
- Cache invalidation/purge was not triggered after data changed.
- Different geographic POPs may hold different versions.
5. Service Worker Cache (PWA)
What: A script running in the browser that can intercept network requests and serve cached responses from the Cache Storage API.
How: The service worker’s fetch handler may return a cached response before attempting a network request.
Why it becomes stale:
- Cache‑first strategies prioritize stored assets over fresh network data.
- Service worker is not updated or unregistered after a deployment.
6. Duplicated Local React State (Not a formal cache)
What: A component copies a prop or API result into its own useState value.
How: The state is initialized once; later updates to the source are not reflected automatically.
Why it appears stale:
- The UI renders the snapshot instead of the live source.
- Developers forget to synchronize the local state after receiving fresh data.
10‑Second Debug Guide
Use the following decision tree to locate the stale source quickly.
- If no request appears in the Network panel → Check React Query cache, then duplicated local state, then Service Worker.
- If a request exists but the response payload is old → Inspect Browser cache, then CDN cache, then Next.js fetch cache.
- If the response is fresh but UI does not update → Verify React Query invalidation and local state synchronization.
How to Prevent Stale UI
Set caching behavior intentionally for each layer.
- React Query: Choose appropriate
staleTime, usequeryClient.invalidateQueriesafter mutations, and keep query keys consistent. - Next.js: Use
fetch(..., { cache: 'no-store' })for user‑specific data, or configurerevalidateintervals that match data volatility. - Browser: Send precise
Cache‑Controlheaders (e.g.,no-cache, must-revalidate) for dynamic endpoints. - CDN: Set short TTLs for personalized content, and automate purge calls on data changes.
- Service Worker: Apply
networkFirstorstaleWhileRevalidatestrategies for API calls, and unregister during major deployments if needed. - Local State: Render directly from the source when possible; if a copy is required, synchronize it with
useEffecton source changes.
Summary
Stale UI is rarely random; it is almost always the result of an overlooked cache layer. By understanding the five primary caches—React Query, Next.js fetch, Browser HTTP, CDN, Service Worker—and the non‑cache pitfall of duplicated local state, developers can quickly diagnose and fix the root cause, ensuring that the UI always reflects the latest data.