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
| Option | Type | Default | Description |
|---|---|---|---|
remote | string | โ | Remote adapter type or connection |
strategy | string | "last-write-wins" | Conflict resolution strategy |
interval | number | 10000 | Sync 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`);
});