Skip to content

Sync engine

Sync engine

Pod ships a native sync engine — not a plugin, bolt-on cache, or third-party replication layer. Tenant apps read and write through $pod/client; when you deploy on Norbital cloud, Core hosts and proxies the server-side sync transport.

Live reads

Every read is a live query against a policy-scoped local PGlite replica. Use client.db.<collection>.findMany, findFirst, or count — filters, sorts, pagination, and relations compile to local SQL. When a mutation lands (yours or someone else's), the engine re-evaluates every live query that depends on the changed collections and diffs the result into the reactive value.

import { client } from '$pod/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.

Keyset pagination uses the same cursor format locally and on the server, so pages stay consistent as the replica warms up.

Optimistic writes

Mutations go through create, update, and delete on client.db. The sync engine applies the change to a local overlay on the same frame so the UI responds instantly. The server confirms or rejects asynchronously through collection_ops — permissions, hooks, audit, history, approvals, and versioning always apply. A rejection rolls back the overlay and surfaces the reason.

import { client } from '$pod/client';

await client.db.claims.create({
  employee_id: employeeId,
  amount: 1500,
  description: 'Travel reimbursement'
});
// UI updates same-frame. Server confirms or rejects through collection_ops.

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 — no invalidate, refetch, or revalidate in app code.

Policy-scoped local replica

The client maintains one PGlite database per origin. Catch-up syncs whole collections under policy — filters, sorts, and pagination are pure local SQL over warm tables. Rows outside policy scope never reach local storage; the server evicts them with leave events on the change stream.

When the browser supports it, a SharedWorker owns the replica so multiple tabs share one catch-up and one set of tables. Reload opens PGlite with tables already populated, renders from local data on the first frame, then reconnects the stream at the persisted cursor.

Resident and windowed collections

A collection is resident when its policy-scoped rows fit the residency cap. Everything about a resident collection — filter, sort, page, count, relations, search — is local and instant.

Above the cap it is windowed. The replica holds a working set built from queries the app actually makes; primary-key lookups that hit stay instant even on large collections. Some reads (counts, search, incomplete pages) still go to the server when a window alone would produce a wrong answer rather than a stale one.

Not the same as pod sync or Studio preview sync
Pod sync engine — live data queries and optimistic writes in running tenant apps.
pod sync CLI — filesystem compiler sync that generates .norbital/ types and registries before build.
Workspace Studio preview sync — checkpoint build that applies DDL and records an immutable release artifact. See Workspace Studio.