# 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.

```ts
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:

```ts
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](/docs/engine/workers.md) 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. |

---

Minnow 0.1.0 · this page on the site: /docs/client/live/
