ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-06-13Advanced

Keeping TanStack Query v5 Cache Consistency Intact — Invalidation Boundaries, Optimistic Updates, and SSR Traps, Worked Through with Antigravity

A like that snaps back a moment after you tap it; a stale value that lingers when you return from another tab. This walks through the three places TanStack Query v5 cache consistency breaks, with working code for invalidation boundaries, onMutate rollback, and per-request QueryClient isolation.

antigravity345TanStack QueryReact QueryNext.js5TypeScript9cache designstate management2

Premium Article

You tap "like," the heart turns red, and a fraction of a second later it slides back to grey. The server returned 200, yet the screen is lying. The first time I saw this in a personal app, I reread the mutation code several times. It looked exactly like the textbook version, but the display kept reverting now and then. The culprit was neither onError nor mutationFn — it was a separate fetch that had started just before the mutation.

Most TanStack Query v5 (formerly React Query) defects take this shape: they look like isolated bugs but are really cache-consistency design problems. The library itself is well made, and each individual API is straightforward. The moment several queries and mutations begin sharing one cache, though, you suddenly need to decide how consistency is preserved. Antigravity's AI agent will write the hook boilerplate in seconds, but this one question — where consistency is guaranteed — has to stay in the hands of whoever reads the generated code, or it falls apart.

As an indie developer, here I will sort the inconsistencies I actually hit during my own development by the place they occur and close them one at a time. Rather than lining up code fragments, sharing "why it breaks there" first tends to help tomorrow's code more.

The cache usually breaks in only three places

After running this for a few years, what I noticed is that TanStack Query inconsistencies concentrate in roughly three spots. First, the spot where the invalidation boundary after a mutation is too wide or too narrow. Second, the spot where the optimistic update's rollback path is missing. Third, the spot where SSR shares a QueryClient and one request's data bleeds into another.

Put differently: when you meet a new bug, asking "which of the three is this?" narrows the search dramatically. The reverting-heart example above looks like the second, but it was actually a collision between invalidation and the optimistic update — a problem sitting on the line between the first and second. Let's go in order.

First, the v5 baseline — bake isPending and signal into the template

Before the consistency discussion, just two foundations from v5. Unlike v4, status: 'loading' was renamed to pending, and isPending (cache empty, still loading) and isFetching (refetching but the old data is still shown) are now clearly separated. Blur this distinction and you get a flickering UI that flashes a skeleton on every refetch.

import { useQuery } from "@tanstack/react-query";
 
export function useUserProfile(userId: string) {
  return useQuery({
    queryKey: ["users", userId, "profile"],
    // always receive signal and pass it to fetch — tied to aborting on unmount
    queryFn: ({ signal }) => fetchUserProfile(userId, { signal }),
    staleTime: 60_000,
    gcTime: 5 * 60_000,
    enabled: Boolean(userId),
  });
}
 
async function fetchUserProfile(userId: string, { signal }: { signal: AbortSignal }) {
  const res = await fetch(`/api/users/${userId}`, { signal });
  if (!res.ok) throw new Error(`Failed to fetch user: ${res.status}`);
  return (await res.json()) as UserProfile;
}

Receive signal as an argument to queryFn and pass it to fetch. This was possible in v4, but in v5 it became the standard with "no reason to skip it." Ask Antigravity to "write a user-fetch hook" and you'll sometimes get a template that drops signal. I keep this on the checklist I run before merging generated code. Whether you can stop a request on unmount matters more to server load the more navigation-heavy the app is.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A diagnostic lens that isolates the three places cache inconsistency is born: invalidation boundaries, optimistic rollback, and SSR client sharing
Templating the five steps (cancelQueries to snapshot to setQueryData to onSettled) so revert bugs disappear structurally
Why QueryClient must be created per request, and how a singleton becomes a personal-data leak
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-03-25
Antigravity + tRPC: Build Type-Safe Full-Stack APIs with End-to-End Type Inference
Learn how to combine Antigravity's AI agents with tRPC to build fully type-safe APIs from server to client. Covers Zod validation, React Query integration, middleware patterns, and practical development workflows.
App Dev2026-04-15
Antigravity × Firebase Data Connect: Building Type-Safe GraphQL APIs Faster with AI
A complete implementation guide for Firebase Data Connect. From GraphQL schema design to Firebase Auth integration, Antigravity AI-assisted query generation, and production deployment—all with working code examples.
App Dev2026-06-12
Before Android 17 Stops Honoring Portrait Lock — Auditing Four Wallpaper Apps for Large-Screen Resizability
How I audited four portrait-locked wallpaper apps with an Antigravity agent before Android 17 starts ignoring orientation and resize restrictions on large screens.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →