Miles Tanaka
All posts
Architecture

Local-first is harder than it looks

March 14, 2026·6 min read

Local-first sounds simple until you actually try to sync two devices that both edited the same note offline. I picked a CRDT library for Fieldnote expecting it to solve merging for me. It solves merging. It does not solve the ten other things I assumed came with it.

Conflict-free doesn't mean conflict-invisible. Two people editing the same paragraph still produces a merged result that reads like nonsense to a human, even if it's mathematically consistent. I ended up building a simple diff view so users can see when a merge happened, rather than trusting it silently.

The other surprise was storage growth. CRDTs keep tombstones and operation history to make merging possible, and that history grows forever unless you actively compact it. For a note-taking app, that's the difference between a 2KB file and a 200KB file after a year of daily edits.

None of this makes local-first the wrong choice — it's still the right one for Fieldnote. It just means the pitch ('it just syncs') hides a lot of engineering that has to happen before it's true.