Skip to content
qt

Why query-tags?

Your mutations shouldn't know about your queries

Manual cache invalidation is the hidden coupling tax you pay on every feature. Here's why it hurts, and how tag-based invalidation fixes it for good.

The Problem

Every mutation knows about every query

As your app grows, each mutation accumulates a list of query keys it must invalidate. Add a new query? Update every mutation that might affect it. It's hidden coupling, and it compounds.

Manual invalidation
// In your "createTodo" mutation handler
const addTodo = useMutation({
  mutationFn: createTodo,
  onSuccess: () => {
    // You need to remember EVERY query that touches todos
    queryClient.invalidateQueries({ queryKey: ['todos'] })
    queryClient.invalidateQueries({ queryKey: ['todos', 'count'] })
    queryClient.invalidateQueries({ queryKey: ['todos', 'recent'] })
    queryClient.invalidateQueries({ queryKey: ['stats'] })
    queryClient.invalidateQueries({ queryKey: ['dashboard'] })
    // Did I get all of them? What about the other tab?
    // What about the route loader?  New teammate added a query — now out of sync.
  }
})
With query-tags
// On the server, once, in your action handler
await tagInvalidation.invalidateTags({
  tags: [appTags.todos()]
})

// That's it. Every query tagged with "todos.*" updates.
// Every tab. Every loader. Every component. Automatically.
// New query added? Just tag it — zero mutation changes needed.
Every new query you add requires updating every mutation that could affect it. With tags, new queries auto-participate — zero mutation changes needed.

Mutation drift

New queries are added but mutations aren't updated. Stale data silently appears.

Cross-tab blindness

queryClient.invalidateQueries() only affects the current browser tab.

Loader amnesia

Route loaders re-run on navigation, not on data mutation — missed refetches everywhere.

Comparison

query-tags vs alternatives

How does it stack up against rolling your own or using Next.js revalidateTag?

FeatureManualNext.js
revalidateTag
query-tags
Type-safe tag references
Multi-tab sync
Hierarchical invalidation
Per-tenant scoping
Route loader refresh
Works with TanStack Query
No framework lock-in
~
Debug tooling
~

Ready?

Get started in 5 minutes

Follow the step-by-step guide to add query-tags to your TanStack Start app.

Read the guide →