Syncular keeps an SQLite database on each client and synchronizes it through a server-owned commit log. Apps read from local SQLite and continue to work offline. A write updates local state immediately, enters an outbox, and is checked by the server when it syncs.
The browser client runs SQLite on OPFS. Native integrations share the Rust core
and native SQLite across Rust, Swift, Kotlin, Flutter, React Native, and Tauri.
Servers run on Bun, Node, or Cloudflare Workers with SQLite, Postgres, or D1.
Backend services and workers can run a
server-side SyncClient with
persistent SQLite (often called a headless client). A
database-less SyncRemoteClient
submits commits and calls registered server operations. Applications can store
domain actions as event rows
alongside their related writes.
Documentation · Quickstart · Live demos · Benchmarks · Blog
bun create syncular-app my-app --template minimalThe minimal template creates a server, a schema, two independent clients, and a smoke test. The five-minute quickstart walks through the generated project and runs the two clients against each other.
Syncular is pre-1.0 and currently maintained by me,
Benjamin Kniffler. The wire protocol is written
down and checked across two implementations. Public APIs and protocol details
can still change before 1.0. Changes are recorded in
docs/RELEASE.md.
docs/SPEC.md defines the sync wire protocol,
docs/REMOTE.md defines registered remote operations, and
spec/vectors/ contains its byte-level fixtures. The
TypeScript and Rust cores run the same implementation-independent conformance
catalog. A behavior change that affects both cores has to update the spec and
add a conformance scenario.
Integration tests use an in-memory transport with deterministic fault
injection. They wait for explicit readiness signals; sleeps are banned. A small
set of adapter tests exercises real sockets. The details live in
packages/conformance.
| Path | What it contains |
|---|---|
packages/core |
Protocol codecs, shared types, vector round-trips |
packages/server |
Server protocol handler plus storage and authorization interfaces |
packages/server-hono, packages/server-workers |
Hono and Cloudflare Workers bindings |
packages/web-client |
@syncular/client, the TypeScript client core on SQLite |
packages/react |
React hooks over the client |
packages/typegen |
Schema and query compiler with TypeScript, Swift, Kotlin, Dart, and Rust output |
packages/crypto, packages/crdt-yjs |
Column encryption and Yjs CRDT integration |
packages/testing |
@syncular/testkit, an in-process server and clients |
packages/conformance |
The scenario catalog both cores run |
rust/ |
Rust client core, command surface, and C FFI |
bindings/ |
Tauri, React Native, Swift, Kotlin, and Flutter bindings |
apps/docs |
The syncular.dev source |
bun install
bun run check # typecheck + lint + testRead AGENTS.md before contributing. It contains the rules that
apply to maintainer work and external contributions.
This README has had plenty of LLM help. So has the rest of the project: docs,
tests, benchmarks, production code. Syncular itself wasn't prompted into
existence though; I've spent years on offline-first problems, built
debe back in 2019, and studied
PowerSync, Zero, Electric, Replicache, Turso, LiveStore, and Jazz closely
before writing this engine. The concepts and their first implementations are
hand-written, and the checks above apply to every diff no matter where it
came from. The full story is at
syncular.dev/llms.
Contributions with LLM help are welcome. If a model drafted or rewrote something that's still in your pull request, say so in the description. Read your own diff and be ready to explain it; pull requests pasted straight out of a model are closed without comment.