Live data
Live data
This is how a tenant app touches data. Reads are live queries , writes are optimistic mutations , and both go through $bolt/client — you never open a connection, manage a cache, or invalidate anything. Bolt’s sync engine keeps every client current; this page is the author-facing half of that contract.
Reads are live queries
Every read is a live query executed as local SQL against a policy-scoped replica of your data. Use client.db.<collection>.findMany , findFirst , or count — a read that is a filter, a sort, and a limit compiles to local SQL through the same compiler the server uses, so it is instant and never leaves the device. Relationship expansion, free-text search, aggregates, and history are answered by the server instead: a local answer that is merely close is worse than a remote one that is right. When a change lands (yours or someone else’s), the engine re-evaluates every live query that depends on the changed collection and diffs the result into the reactive value.
import { client } from '$bolt/client';
const orders = client.db.orders.findMany({
where: { status: { eq: 'open' } },
with: { customer: true },
orderBy: { created_at: 'desc' }
});
// Live — another tab or automation closes an order and this result updates. The replica is built once, before any of that. It provisions itself from the tenant’s own migrations, then takes a paged snapshot of every collection this user may read, and starts streaming from the cursor that snapshot handed back. The change log alone could not do it: only writes through the collection runtime reach the outbox, so seeded and imported rows are absent from it entirely.
Writes are optimistic mutations
Browser writes use client.db.<collection>.mutate(values) . It returns Promise<void>; successful completion invalidates affected live queries. client.db.<collection>.pending is a numeric in-flight count, so concurrent writes settle independently.
client.db.cost_estimates.mutate(values)
values = precisely typed root + any explicitly included relationship state
│ pending += 1
▼
server: policy → approvals → before hooks → reconcile the
root + every included relationship → after hooks → audit
│ (one transaction)
┌──────────┴───────────┐
▼ ▼
committed refused
affected queries reason surfaces;
invalidate nothing was written
│ │
└──────────┬──────────┘
▼ Promise<void> resolves; pending -= 1
affected live queries re-run and the outbox carries the
committed change to every other replica An included relationship is its complete desired state. Rows present in it are inserted or updated; previously stored rows absent from it are deleted. Explicitly included relationships synchronize recursively, while omitted relationships remain untouched. The root and all included relationships reconcile atomically.
Generated types describe that nested graph without casts or compatibility wrappers. Queries own current, loading, and error; mutations own pending. Components do not duplicate query data, refresh, loading, error, or mutation state.
import { client } from '$bolt/client';
await client.db.cost_estimates.mutate(values);
// The included relationship is its complete desired state. Present rows are
// inserted or updated; stored rows omitted from it are deleted. Relationships
// omitted from the mutation are untouched. Explicit nesting reconciles
// recursively, and the whole submitted graph commits atomically.
client.db.cost_estimates.pending; // numeric in-flight count mutate never returns a record: write-only and row-filtered policies may permit a write without permitting the matching read. The live query is the only source for data the caller may see. This browser mutation surface does not define a top-level record-delete encoding.
The invariant
The read path never waits for data this device has already seen. Every server answer is folded into the local replica — the second visit to anything is instant, with no invalidate , refetch , or revalidate anywhere in app code.
Related guides
- Collections — define the models live queries read
- Apps — compose operational UIs on top of live reads
- Sync engine — how the replica, change feed, and transport work
- Policies — scope what reaches the local replica