Define tags
defineTags({
todos: {
list: () => ["todos"],
byId: (id) => ["todo", id],
}
})Create a typed tag tree. Full autocomplete, compile-time safety.
@tanstack-tools/query-tags
Tag-based cache invalidation for TanStack Start, Query & Router. One invalidateTag() on the server. Every subscribed query updates. Every tab. Automatically.
Every mutation must know about every query it affects. Add a query, update every mutation. Forget one? Stale data. Tags flip this: queries declare what data they need, and the server invalidates by meaning — not by key.
See the full comparison →Try it now
Add a todo and watch both query panels update automatically. No invalidateQueries anywhere in the mutation code.
Get groceries
Buy a new phone
Finish the project
3
todos.list3 total
todos.summaryAdd a todo and watch both panels flash green simultaneously — zero manual invalidation
How it works
defineTags({
todos: {
list: () => ["todos"],
byId: (id) => ["todo", id],
}
})Create a typed tag tree. Full autocomplete, compile-time safety.
useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
meta: { tags: [appTags.todos.list()] }
})One line in meta. Or use withTags() for zero-boilerplate.
await tagInvalidation.invalidateTags({
tags: [appTags.todos()]
})
// Every tagged query refreshes.Server decides. Clients react. SSE delivers. Done.
Comparison
How does it stack up against rolling your own or using Next.js revalidateTag?
| Feature | Manual | Next.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 | ~ | ✕ | ✓ |
9
entry points
37+
live demos
0
manual refetches
100%
TypeScript
Built for TanStack
Invalidate a parent tag and all children refresh automatically. No more listing every query key.
SSE pushes invalidation to all connected clients. Open two tabs — they just sync.
Per-user, per-tenant, or global scopes. Multi-tenant apps get isolation for free.
See every SSE event, every tag match, pause/resume the system. Full observability.
Explore
Tagged queries, group invalidation, mutation patterns — the fundamentals.
Explore →Products, cart, admin panel. Watch a price change propagate everywhere.
Explore →Posts, comments, likes, live feed. Multi-user real-time updates.
Explore →Multi-tab sync, reconnection recovery, scope isolation, optimistic updates.
Explore →Get started
Add the plugin, define your tags, and never write a manual invalidateQueries again.