Offline-first bidirectional database sync. Sequence numbers for speed, Merkle trees for correctness.
Clients keep a local SQLite database that syncs with a Postgres-backed server over Phoenix channels. Writes happen locally and sync when connected — no loading spinners, no network dependency for reads.
Client (SQLite) Server (Postgres)
┌─────────────┐ WebSocket / Phoenix ┌──────────────────┐
│ local writes │── push ─────────────► │ apply + broadcast │
│ │◄─ pull ────────────── │ seqnum triggers │
│ merkle tree │◄─ verify ──────────► │ row hashes │
└─────────────┘ └──────────────────┘
Layer 1 — Sequence numbers: Every write gets a monotonically increasing seqnum. Clients track the last-seen seqnum per table and pull only newer rows. Fast incremental sync.
Layer 2 — Merkle trees: Periodic SHA256-based integrity checks compare hash roots between client and server, drill into differing blocks, and repair only the rows that drifted. Cryptographic correctness guarantee.
| Repo | Description |
|---|---|
| synclib-server | Elixir/Phoenix sync server with seqnum triggers, Merkle verification, and scoped broadcasting |
| Repo | Description |
|---|---|
| synclib-client-js | TypeScript sync client — channels, push/pull, Merkle verification |
| synclib_client_flutter | Dart/Flutter sync client — same capabilities, native mobile + desktop |
| Repo | Description |
|---|---|
| synclib-js | TypeScript/JavaScript SQLite wrapper with automatic change tracking |
| synclib_flutter | Dart/Flutter SQLite wrapper with automatic change tracking |
| Repo | Description |
|---|---|
| synclib-hash | Cross-platform Merkle tree hashing (WASM + native) |
| pg-synclib-hash | PostgreSQL extension — computes row hashes at write time via triggers |
| Repo | Description |
|---|---|
| synclibc | C library for SQLite change tracking — compiled to native and WASM, used by all client wrappers |
| Repo | Description |
|---|---|
| synclib-firestore-flutter | Dart/Flutter Firestore-compatible API for local SQLite via synclib |
| synclib-firestore-js | TypeScript Firestore-compatible API for local SQLite via synclib |
import { SyncClient, ChannelRole } from 'synclib-sync';
const client = new SyncClient({
db,
serverUrl: 'wss://api.example.com/socket',
clientId: 'device-abc',
channels: [{
topic: 'sync:user:user-123',
role: ChannelRole.PUSH,
tables: [{ name: 'todos' }],
}],
});
await client.initialize();
await client.connect(token);import 'package:synclib_sync/synclib_sync.dart';
final client = SyncClient(SyncClientConfig(
database: db,
serverUrl: 'wss://api.example.com/socket',
clientId: 'device-abc',
channels: [
SyncChannel(
topic: 'sync:user:user-123',
role: ChannelRole.push,
tables: [SyncTable('todos')],
),
],
));
await client.initialize();
await client.connect(token: token);mix deps.get && mix ecto.setup && mix phx.serverImplement the 6 behaviours for your use case — channel joins, snapshot queries, change handling, broadcast routing, connection hooks, and schema management.
- Offline-first — local SQLite with automatic change tracking. Works without a connection, syncs when online.
- Bidirectional — push, pull, or bidirectional per channel. Per-table direction overrides.
- Schema migrations — server-driven. Clients receive SQLite DDL over the sync channel and apply automatically.
- Multi-platform — TypeScript for web/Node.js, Dart/Flutter for iOS/Android/desktop, Elixir for the server.
- Phoenix channels — persistent WebSocket connections with scoped broadcasting (user, group, world).
- JWT auth — HS256 and RS256 token verification on every connection.
- Extensible — custom message types, conflict resolvers, and server-side behaviours.
synclibc (C)
├── synclib_flutter (Dart FFI)
│ └── synclib_client_flutter (sync client)
│ └── synclib-firestore-flutter (Firestore API)
├── synclib-js (TypeScript, WASM)
│ └── synclib-client-js (sync client)
│ └── synclib-firestore-js (Firestore API)
└── synclib-hash (WASM + native)
└── pg-synclib-hash (Postgres extension)
synclib-server (Elixir/Phoenix)
├── seqnum triggers
├── merkle verification
├── scoped broadcasting
└── schema management
All repositories are MIT licensed.