All posts
Synapse TeamClientsSeptember 24, 20267 min read

Designing offline-first sync

Offline-first sounds like a caching problem. It is really a conflict problem, and the fix is to stop pretending there is only one timeline.

Every device has a truth

Each client writes to a local store immediately and never blocks the interface on the network. Two devices can compose in the same thread at the same time, so the merge has to be meaningful instead of last-write-wins.

Messages carry causal metadata rather than a clock. Order comes from what depended on what, which is why a reply never lands above the message it answers.

Drafts are the hard case

A draft is unsent, so it has no id. We give it a temporary one, then swap it when the first keystroke is sent, and the swap is what previously duplicated text.

The fix was boring: the local store became authoritative for unsent state, and reconnect reconciles against it instead of overwriting it.

What we measurably gained

Compose latency on a saturated connection dropped to the same cost as a local write. Failed sends are now visible as failures rather than mystery hangs, which reduced related support tickets to nearly nothing.

Want to try what this post describes?

Install a client, or run a node of your own — both are MIT licensed.

Download Synapse
Next postBuilding a release bot with the Synapse CLIForty lines of TypeScript, one signed webhook, and a channel that tells you the truth about your deploys.

Built in public, written up as we go

New posts land with each release. Subscribe through the repository releases page.