Sync rules & buckets
Copy page
Sync rules declaratively scope which rows each authenticated client may sync. They are evaluated server-side; the client never receives out-of-scope data.
defineSyncRules((b) => ({ ruleName: b.bucket({ parameters: (actor) => /* how to discover bucket keys */, data: (bucket) => [ /* scoped queries per bucket */ ], }),}));Each rule has:
- parameters — yields bucket column bindings for this actor (from JWT, membership table, or static mapping)
- data — one or more table queries, each constrained to bucket keys
Bucket parameters
Section titled “Bucket parameters”Static column mapping
Section titled “Static column mapping”parameters: () => b.params({ ownerId: "owner_id" }),The client supplies concrete bucket values via bucketsForSyncRule on createNizhalClient.
Membership table
Section titled “Membership table”parameters: (actor) => b.membership({ table: "shop_members", where: { user_id: actor.userId }, select: { shopId: "shop_id" }, }),The server resolves membership with bound parameters — no raw SQL in app code. When membership shrinks, pull returns removedBuckets and the client purges local rows (REQ-14).
Data queries
Section titled “Data queries”data: (bucket) => [ b.table("notes").where(b.eq("owner_id", bucket.ownerId)), b.table("tags") .where(b.eq("owner_id", bucket.ownerId)) .related([b.table("tag_links").where(b.eq("owner_id", bucket.ownerId))]),],Every query must include at least one b.eq(column, bucket.key) predicate. The builder rejects raw SQL in data queries.
No-leak lint
Section titled “No-leak lint”defineSyncRules calls assertSyncRulesNoLeak at registration time. Violations throw SyncRuleLintError with rule name and query index.
This is not middleware — it is a typed, linted language for subset sync. If a predicate forgets to scope by bucket, the rule fails at build time (or test time), not in production with a data leak.
Server evaluation
Section titled “Server evaluation”On pull, the server:
- Resolves parameters for the authenticated actor
- Intersects with client-requested buckets
- Runs each
dataquery with bucket bindings - Returns changed rows + tombstones +
removedBuckets