Live queries
Subscribe to a query and get a fresh result after every commit that could change it.
Any select builder becomes a live query with .live(). Subscribers get the current result
immediately, then a fresh result after any commit that could have changed it.
const live = db
.selectFrom("orders")
.select(["order_id", "status", "total"])
.where("status", "=", "pending")
.live();
const subscription = await live.subscribe({
onChange(rows) {
render(rows); // Array<{ order_id: number; status: string; total: number }>
},
onError(error) {
console.error(error);
},
});
// later
await subscription.close();The rows are typed exactly as execute() would return them, and typeof live.$inferRow gives you
that type without running anything.
As an async iterable
LiveQuery is also an AsyncIterable, which suits a for await loop or any consumer that prefers
pull to push:
for await (const rows of live) {
render(rows);
if (done) break; // breaking closes the subscription
}Breaking out of the loop closes the subscription immediately rather than waiting for the next change — worth knowing if you are cancelling a view that may sit idle for a long time.
What triggers a re-run
A subscription records the tables its query depends on. A commit touching a dependency re-runs the
query; a commit that cannot affect it does not. Identical results are suppressed, so a re-run that
produces the same rows does not call onChange.
Correctness never depends on a notification arriving. Each check reconciles against the current committed version in storage, so a missed or duplicated cross-tab hint cannot produce a stale result — it can only delay a fresh one.
Across tabs and workers
Live queries work the same whether the engine runs in this thread or in a worker. When several tabs share a database, commits in one tab reach subscriptions in another; see Workers & multi-tab for the coordination details and options.
Handlers
| Handler | When |
|---|---|
onChange(rows) | The initial result, then every changed result. |
onError(error) | A re-execution failed. The subscription stays open. |
onComplete() | Once, when the subscription or its owning set closes. |