Skip to main content

@monlite/sync — local-first replication

Replicate a local monlite database to/from MongoDB, PostgreSQL, MySQL, another monlite, or memory. Pull / push / two-way / live, with last-write-wins or custom conflict resolution.

npm install @monlite/sync
import { createDb } from "@monlite/core";
import { sync, MongoAdapter } from "@monlite/sync";

const db = createDb("app.db", { sync: true });

const engine = sync(db, {
adapter: new MongoAdapter({ client: mongo, db: "app" }),
collections: ["users", "orders"], // or "*"
mode: "two-way", // "pull" | "push" | "two-way"
conflict: "lww", // or (ctx) => "local" | "remote"
interval: 5000, // poll cadence (optional)
retries: 4, // retry a failed round before failing
});

await engine.start(); // bootstrap + begin syncing
await engine.sync(); // force one round
engine.status(); // { running, pendingPush, conflicts, cursor, … }
await engine.stop();

Adapters

AdapterUse
MongoAdapterMongoDB (change streams for live)
PostgresAdapterPostgreSQL (jsonb tables) — local runtime, Postgres as cloud-of-record
MySqlAdapterMySQL / MariaDB (json tables)
MonliteAdaptermonlite-to-monlite (multi-device via a shared hub)
MemoryAdaptertests / reference implementation

Resilience

A flaky network won't drop data: failed pull/push retry with exponential backoff (retries, retryBaseMs), and a change is marked pushed only on remote ack — anything unacked re-sends next round (idempotent via LWW). The pull cursor advances only after a batch fully applies.

Both document and structured collections sync. Write a custom adapter for any other backend.