Local schema & DDL parity
The client runs a local PGlite database whose schema is generated from your sync registry. It is a read cache plus write-staging buffer — not a mirror of your Postgres schema. This page is precise about what it does and does not replicate.
The governing fact behind everything below: the client only ever holds a filtered subset of rows (whatever the shapes stream down), and the server is always the integrity and security authority.
What the local schema generates today
Section titled “What the local schema generates today”From the registry, generateLocalSchemaSql emits:
- Enum types —
CREATE TYPE … AS ENUMfor every enum on a projected column. (You do not hand-provide enums; they are automatic. TheprepareLocalDbBeforeSchemahook is only for non-enum prerequisite objects.) - The synced table — its projected columns, their types (including arrays),
NOT NULL, and the primary key (single or composite). - For writable tables: the overlay table, the mutation journal + its sequence and indexes, a reconcile trigger + function that clears overlay/journal rows when the sync echo arrives, and a read-model view that unions the overlay over the synced row.
That is the whole of it. In particular, the synced table carries no defaults, no constraints beyond the primary key, and no foreign keys today.
Never local — server authority, by nature
Section titled “Never local — server authority, by nature”These belong to the server and will not be replicated locally; doing so would be redundant at best and divergent at worst:
- Row-level security, policies, and governance enforcement. Security is asserted when a write reaches Postgres — see The write path.
- Triggers, functions, and materialized views (other than the client’s own reconcile trigger and read-model view).
- Managed-field values (e.g. owner via
authClaimat claimPath["sub"],created_at_us/updated_at_usvianowMicroseconds). These are deliberately assigned by the database, not defaulted locally — their server-side DEFAULTs callpublic.pgxsinkit_clock_us(), a server-only function never rendered into the local PGlite DDL (registry defaults aren’t emitted locally at all).
Not yet local — gaps we intend to narrow
Section titled “Not yet local — gaps we intend to narrow”These are currently omitted but are fidelity gaps, not principles. The intent is to narrow them over time on a best-effort basis against the synced subset — catching obvious violations before a flush, while the server stays authoritative:
- Static (non-managed) column defaults — could prefill a staged row to match what the server would produce.
- CHECK constraints and generated columns — single-row and locally computable, so they could validate or derive before flush.
- FOREIGN KEY and UNIQUE — only ever enforceable against the rows the client holds (the parent may be unsynced; uniqueness is unknowable across a partial dataset), so any local form is explicitly best-effort and never a substitute for the server check.
Until then, validate user input on the client (e.g. with Zod) and rely on the server to reject what PGlite would not.
Practical implications
Section titled “Practical implications”- Don’t rely on a local default, CHECK, FK, or UNIQUE firing today — they aren’t emitted yet.
- Because the local schema has no foreign keys, you never need
deferrableConstraintsfor the local apply — even when a child and its parent sync in one consistency group.deferrableConstraintsgoverns only the server apply, where the FKs are real and a batch may stage a parent and child together. - Enums are created locally; other prerequisite objects go through
prepareLocalDbBeforeSchema. - Treat the server as the only place integrity and security are guaranteed; the local schema exists to serve fast offline reads and to stage optimistic writes.