Persist

Sync & Conflict Resolution

Configure automatic sync strategies and conflict resolution for Persist stores.

Sync & Conflict Resolution

How sync works

Persist is offline-first. Writes go to the local store immediately and never block on network. A background sync queue pushes changes to the remote and pulls remote changes back.

local write --> local store --> sync queue --> remote
                                   ^
                                   |
                         pull remote changes

Configuration

import { createStore } from "@cuitty/persist";

const store = await createStore({
  name: "my-app",
  adapter: "sqlite",
  path: "./data/my-app.db",
  sync: {
    remote: "postgres",
    strategy: "last-write-wins",
    interval: 5000, // sync every 5 seconds (default: 10000)
  },
});

Options

OptionTypeDefaultDescription
remotestringโ€”Remote adapter type or connection
strategystring"last-write-wins"Conflict resolution strategy
intervalnumber10000Sync interval in milliseconds

Strategies

Last-write-wins (LWW)

The simplest strategy. Each record carries a timestamp; the most recent write wins on conflict.

sync: {
  remote: "postgres",
  strategy: "last-write-wins",
}

Good for settings, preferences, and data where overwrites are acceptable.

CRDTs

Conflict-free replicated data types that merge automatically without data loss. Best for collaborative data.

sync: {
  remote: "postgres",
  strategy: "crdt",
}

Persist uses operation-based CRDTs under the hood. Counters, sets, and maps merge deterministically across peers.

Custom merge

Supply a function that receives both versions and returns the resolved value.

sync: {
  remote: "postgres",
  strategy: "custom",
  merge(local, remote) {
    // Example: keep the record with more fields
    const localKeys = Object.keys(local.value);
    const remoteKeys = Object.keys(remote.value);
    return localKeys.length >= remoteKeys.length ? local : remote;
  },
}

Conflict resolution callbacks

Register a callback to handle conflicts interactively or log them.

store.events.on("conflict", (event) => {
  console.log(`Conflict on key: ${event.key}`);
  console.log("Local:", event.local);
  console.log("Remote:", event.remote);
  console.log("Resolved:", event.resolved);
});

Offline-first behavior

When the device is offline, Persist continues to accept reads and writes against the local store. Changes accumulate in the sync queue and flush automatically when connectivity returns.

The sync queue is persisted to disk, so pending changes survive app restarts.

Monitoring sync status

const status = store.sync.status();
// { state: "synced" | "syncing" | "offline", pending: number, lastSync: Date }

store.events.on("sync", (event) => {
  console.log(`Synced ${event.pushed} up, ${event.pulled} down`);
});
Read the same page as Markdown ยท JSON Updated 2026-05-12