Skip to content
Data Modelstable

Offline-first sync and conflict model

Records that live on the device and reconcile with a server: globally-unique IDs, per-record versions, deletes as tombstones, and a deterministic conflict rule — so no acknowledged change is ever silently lost.

When the device holds the authoritative copy until it can sync, the data model has to survive concurrent edits, crashes mid-write, and deletes that must propagate. This spec defines identity, versioning, tombstones, and a deterministic conflict resolution so two devices editing the same record converge on the same answer — and nothing acknowledged is lost.

Entity model

Entity-relationship model

Every syncable record carries a globally-unique ID, a version, timestamps, a soft-delete tombstone, and a dirty flag marking local changes not yet pushed. A per-device sync checkpoint records how far the last successful sync reached.

Offline sync ERD
Offline sync ERD

Definition

Identity and versioning

IDs are globally unique and generated on the client — UUIDs, not sequential integers or timestamp-plus-hash — so two offline devices never mint the same ID for different records. Each record carries a version that increments on every local change, which is what makes a concurrent edit detectable rather than silently overwritten.

Definition

Deterministic conflict resolution

When two versions of a record meet, the winner is chosen by a fixed, total ordering — version, then server-authoritative timestamp, then a stable tiebreak (device ID) — so every peer resolves the conflict identically and the outcome is independent of sync order. Where field-level merge is required, merges are commutative so order still doesn't matter.

Total-order resolution (deterministic on every peer)
-- Winner = higher version; ties broken by server time, then device id.
-- Every device applies the same rule and converges on the same result.
SELECT * FROM candidates
ORDER BY version DESC, server_updated_at DESC, device_id DESC
LIMIT 1;

Definition

Deletes are tombstones

A delete sets `deleted_at` rather than removing the row, so the deletion can propagate to peers that still have the record. Rows are only physically purged after every device has acknowledged the tombstone past its sync cursor — a hard delete before sync is an un-propagatable change that resurrects on the next pull.

Contract

Sync protocol

PhaseRule
PullFetch server changes since the stored cursor
ResolveApply the deterministic conflict rule locally
PushSend dirty records; clear dirty only on server ack
AdvanceMove the cursor only after a fully-acked round
Pull–push–ack cycle

Invariants this spec guarantees

  • Record IDs are globally unique and client-generated; two offline devices never collide.
  • Conflict resolution is deterministic and order-independent — every peer converges on the same record.
  • Deletes propagate as tombstones; a row is never hard-deleted before every device has synced past it.
  • The dirty flag clears and the cursor advances only on server acknowledgement, so a crash mid-sync loses nothing acknowledged.

Want this specified for your system?

We turn definitions like these into the actual schema, policies, and contracts your system runs on. Fixed scope, fixed price, defined delivery date.

Request a Fixed-Scope Architecture Blueprint