Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
// Conditional query — return undefined/null to disable
const
useLiveQuery
(q) =>
if
return
undefined
return
from
todo
where
({ todo }) =>
eq
userId
// When disabled: status='disabled', data=undefined
useLiveSuspenseQuery
// data is ALWAYS defined — never undefined// Must wrap in <Suspense> and <ErrorBoundary>functionTodoList() {
const { data: todos } = useLiveSuspenseQuery((q) =>
q.from({ todo: todoCollection }),
)
return (
<ul>
{todos.map((t) => (
<likey={t.id}>{t.text}</li>
))}
</ul>
)
}
// With deps — re-suspends when deps changeconst { data } = useLiveSuspenseQuery(
(q) =>
q
.from({ todo: todoCollection })
.where(({ todo }) =>eq(todo.category, category)),
[category],
)
useLiveInfiniteQuery
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
useLiveInfiniteQuery(
(q) =>
q
.from({ posts: postsCollection })
.orderBy(({ posts }) => posts.createdAt, 'desc'),
{ pageSize: 20 },
[category],
)
// data is the flat array of all loaded pages// fetchNextPage() loads the next page// hasNextPage is true when more data is available
When a query uses includes (subqueries in select), each child field is a live Collection by default. Subscribe to it with useLiveQuery in a subcomponent:
// In route loader:await todoCollection.preload()
// In component — data available immediately:const { data } = useLiveQuery((q) => q.from({ todo: todoCollection }))
See meta-framework/SKILL.md for full preloading patterns.
Common Mistakes
CRITICAL Missing external values in dependency array
Wrong:
const { data } = useLiveQuery((q) =>
q.from({ todo: todoCollection }).where(({ todo }) =>eq(todo.userId, userId)),
)
Correct:
const { data } = useLiveQuery(
(q) =>
q
.from({ todo: todoCollection })
.where(({ todo }) =>eq(todo.userId, userId)),
[userId],
)
When the query uses external state not in the deps array, the query won't re-run when that value changes, showing stale results.
useLiveSuspenseQuery throws errors during rendering. Without an Error Boundary, the entire app crashes.
Source: docs/guides/live-queries.md
HIGH "Not a Collection" error from duplicate @tanstack/db
If a query-builder alias throws
InvalidSourceError: The value provided for alias "todo" is not a Collection,
it can mean two copies of @tanstack/db are installed. Direct
useLiveQuery(preCreatedCollection) detection is structural and works across
package copies or realms, but q.from({ todo: collection }) still validates
the source with the core collection class.
In dev mode, TanStack DB also throws DuplicateDbInstanceError if two instances are detected.
The root cause is typically a dependency that bundles its own copy instead of declaring @tanstack/db as a peerDependency.
HIGH Tension: Query expressiveness vs. IVM constraints
The query builder looks like SQL but has constraints that SQL doesn't — equality joins only, orderBy required for limit/offset, no distinct without select. Agents write SQL-style queries that violate these constraints. See db-core/live-queries/SKILL.md § Common Mistakes for all constraints.
See also: db-core/live-queries/SKILL.md — for query builder API and all operators.
See also: db-core/mutations-optimistic/SKILL.md — for mutation patterns.
See also: meta-framework/SKILL.md — for preloading in route loaders.