Skip to content
@synclib-io

synclib.io

offline sync and data streams on any platform

synclib

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.

How it works

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.

Synclib supports two Merkle approaches depending on your needs:

  • Server-authoritative hashes (default): The server computes row_hash via Postgres triggers (pg_synclib_hash) and clients store the server-provided value. Merkle comparison checks that client and server have the same data — if hashes differ, the data drifted and gets repaired. This is the simpler approach and is preferred for most sync use cases where the goal is consistency between devices.

  • Client-verified hashes: Clients use synclib_hash directly to compute hashes locally from their own data, then compare against the server's hashes. This verifies correctness — that the data wasn't corrupted in transit or storage. Use this when your application needs to guarantee data integrity beyond just sameness (e.g., financial records, medical data, audit trails).

Both approaches use the same synclib_hash library and produce identical hashes, so they can be mixed. Most applications should start with server-authoritative hashes and add client-side verification only where correctness guarantees are needed.

Repositories

Server

Repo Description
synclib-server Elixir/Phoenix sync server with seqnum triggers, Merkle verification, and scoped broadcasting

Client libraries

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

Database wrappers

Repo Description
synclib-js TypeScript/JavaScript SQLite wrapper with automatic change tracking
synclib_flutter Dart/Flutter SQLite wrapper with automatic change tracking

Hashing

Repo Description
synclib-hash Cross-platform Merkle tree hashing (WASM + native). Used by pg-synclib-hash for server-side computation and available to clients for local correctness verification
pg-synclib-hash PostgreSQL extension — computes row hashes at write time via triggers (server-authoritative)

Core

Repo Description
synclibc C library for SQLite change tracking — compiled to native and WASM, used by all client wrappers

Testing

Repo Description
synclib-test-harness End-to-end test harness for validating sync across clients and server

Firestore compatibility

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

Quick start

TypeScript

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);

Dart / Flutter

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);

Server (Elixir)

mix deps.get && mix ecto.setup && mix phx.server

Implement the 6 behaviours for your use case — channel joins, snapshot queries, change handling, broadcast routing, connection hooks, and schema management.

Key features

  • 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.

Architecture

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

License

All repositories are MIT licensed.


synclib.io

Popular repositories Loading

  1. synclib-io.github.io synclib-io.github.io Public

    HTML

  2. synclib_flutter synclib_flutter Public

    Dart

  3. synclib_client_flutter synclib_client_flutter Public

    Dart

  4. synclib-js synclib-js Public

    TypeScript

  5. synclib-client-js synclib-client-js Public

    TypeScript

  6. synclib-hash synclib-hash Public

    C

Repositories

Showing 10 of 11 repositories

Top languages

Loading…

Most used topics

Loading…