segment on the architecture and lessons learned building a local-first sync engine for Convex
We build software for social workers—people who work in basement shelters with overloaded WiFi, rural homes with zero cell service, concrete buildings where signals die. If a case worker spends 30 minutes documenting an intake and the app spins out, that's asking a vulnerable human to retell their worst moments.
In 2019, Ink & Switch published the defining essay on local-first software. Their seven ideals became our Bill of Rights:
Local-first isn't a dev-twitter trend. It's a user rights issue.
When users edit data offline, conflicts are inevitable. Three approaches:
flowchart LR
subgraph LWW["Last-Write-Wins"]
L1[Simple] --> L2[Fast]
L2 --> L3[⚠️ Field-level]
end
subgraph OT["Operational Transform"]
O1[Powerful] --> O2[Google Docs]
O2 --> O3[❌ Server Required]
end
subgraph CRDT["CRDTs"]
C1[Convergent] --> C2[Offline-First]
C2 --> C3[✅ Character-level]
end
style LWW fill:#ffffcc
style OT fill:#ffcccc
style CRDT fill:#ccffcc
Last-Write-Wins (LWW): Timestamp every change, most recent wins. Simple and fast. For primitive fields (status, priority, title), this is actually fine—if two users change the same field, one wins deterministically. We use LWW for simple fields.
Operational Transformation (OT): Google Docs' approach. Mathematically transforms operations based on concurrent edits. Powerful, but notoriously complex and requires a central server.
CRDTs (Conflict-free Replicated Data Types): For rich text, LWW is unacceptable—you'd lose entire paragraphs. CRDTs merge at the character level. Two users typing in the same paragraph? Both edits preserved.