The Backend Is Optional: Architecting Local-First Sync Without a Source of Truth
The assumption that every application needs a backend to synchronize state is crumbling. A new generation of local-first architectures treats the device as the primary data store, using Conflict-free Replicated Data Types (CRDTs) and Hybrid Logical Clocks to merge changes without coordination. This post examines the architectural trade-offs of building offline-first systems, from mDNS discovery and mTLS pairing to the dual-lane sync model used in production reading apps, and explains when to abandon the cloud as your source of truth.

The “What Was I Reading Last?” Problem
It sounds trivial until you try to build it: tracking reading progress across multiple devices without a central server. Developers building reading apps have encountered the brutal reality that “offline mode” in most SaaS products is a polite fiction, a degraded state where conflicts resolve via last-write-wins, which is really just data loss with extra steps.
When building Merrilin, a reading app designed to work without cloud dependency, the author faced a distributed systems problem disguised as a simple feature. The goal was straightforward: pair two Android phones over WiFi, sync reading positions, annotations, and book metadata, and handle conflicts when both devices updated independently. The result was a 3,390-word technical deep dive and a pull request that would raise eyebrows in any code review.
The complexity reveals itself in the edge cases. When your phone says chapter 12 and your tablet says chapter 8, and both updates happened while offline, someone has to decide where you actually are. Traditional client-server architectures punt this to the server. Local-first architectures solve it on the device using mathematical structures that guarantee convergence without coordination.
The Two Lanes: Guest-Peer vs. Account-Cloud
Merrilin’s architecture splits sync into two distinct lanes, a pattern increasingly common in sophisticated local-first applications:
The Guest-Peer Lane
Operates without any central authority. Two devices on the same WiFi network discover each other via mDNS (Multicast DNS), establish trust through QR-code pairing, and exchange data directly over WebSockets. Local SQLite is the source of truth. The sync protocol uses bidirectional exchange: Device A sends its changes plus a watermark (a cursor tracking “I’ve seen everything up to this point”), Device B calculates what A is missing, and returns those changes in a single POST request. Both sides merge and advance their watermarks.
The Account-Cloud Lane
Activates when you sign in. Now PostgreSQL becomes the source of truth, but the architecture remains local-first. Devices write to a local outbox first (prioritizing reading positions over analytics events), then flush to the server in batches. The cloud pushes updates back via WebSocket or polling, but the client still resolves conflicts locally before applying changes.
The crucial insight is that both lanes carry the same payload, reading positions, annotations, bookmarks, reading events, keyed by SHA-256 file hashes rather than internal IDs. This allows a device to migrate from guest mode to cloud mode by simply replaying its local history through the cloud’s ingest endpoints. No special migration code path required.
Discovery and Trust in a Serverless World
Without a central server, how do devices find each other and establish trust? The answer borrows from decades of distributed systems research and one very specific user experience pattern: SSH.
When you launch the app in guest mode, it starts advertising itself on the local network using mDNS with a custom service type (_merrilin-sync._tcp.). Simultaneously, it browses for other devices advertising the same service. When discovery succeeds, you pair devices using a QR code and 6-digit key. This exchange stores each device’s identity fingerprint and a shared secret.
From that point on, the devices recognize each other by fingerprint, not IP address. If the network changes or IP addresses shift, mDNS helps them rediscover each other, but the fingerprint provides continuity. This is Trust-On-First-Use (TOFU), identical to SSH’s “WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED” model. If a certificate fingerprint doesn’t match during a subsequent connection, the peer gets deactivated immediately. No silent fallback. No retry.
Security operates without a Certificate Authority. Each device generates a self-signed X.509 certificate stored in Android’s Keystore. Connections use mutual TLS (mTLS), where both sides present certificates and verify each other against the stored fingerprints from pairing. Every sync request is additionally signed with the shared secret, covering the HTTP method, path, timestamp, nonce, and request body hash. Even if someone intercepts the TLS connection, they cannot forge requests without the shared secret.
Conflict Resolution Without a Coordinator
The hardest problem in distributed systems, concurrent writes, gets solved differently depending on which lane you’re in.
In the Guest-Peer Lane, neither device is authoritative. Conflicts resolve using timestamps from a Hybrid Logical Clock (HLC), which combines physical wall-clock time with a logical counter. This stays close to real time while guaranteeing consistent ordering even when device clocks drift. For reading positions, the most recent HLC wins (you can only actively read on one device at a time). For annotations, changes merge as a union, if you highlight different passages on different devices, both survive. Deletes are soft-deletes with their own timestamps, so they propagate without erasing history.
In the Account-Cloud Lane, the server can afford to be smarter. It uses version-based Compare-and-Swap (CAS): your device sends “I was at version 8 when I made this change”, and the server either accepts (if version 8 is current) or rejects with the actual current version. But unlike a simple lock, the server looks at intent. If you’re advancing forward in a book, it auto-rebases your update on top of newer versions (up to three retries). If you’re rewinding and there’s a conflict, it rejects immediately, because if another device advanced past you, your rewind is stale.
This dual-model approach recognizes that peers need deterministic merge rules without coordination, while the cloud can leverage its global view to make intent-aware decisions.
The CRDT Reality Check
Most local-first systems pick one consistency model, but production implementations increasingly use CRDTs (Conflict-free Replicated Data Types) for the heavy lifting. CRDTs are data structures where the merge function is commutative, associative, and idempotent, mathematically guaranteeing that all nodes converge to the same state regardless of update order.
| CRDT Type | Merge Semantics | Use Case |
|---|---|---|
| G-Counter | Sum of all node counters | View counts, distributed metrics |
| PN-Counter | Separate increment/decrement counters | Inventory, upvote/downvote scores |
| LWW-Element-Set | Timestamp-based last-write-wins per element | Shopping carts, user preferences |
| OR-Set | Unique tags per add, remove targets specific tags | Collaborative tagging |
| RGA/Logoot | Sequence with unique position identifiers | Collaborative text editing |
For text editing, the most challenging synchronization problem, sequence CRDTs like RGA (Replicated Growable Array) assign globally unique identifiers to each character. When two users insert text at the same position, the merge function sorts by these identifiers, producing a consistent total ordering without coordination. Libraries like Yjs and Automerge have battle-tested these implementations, powering real-time collaboration in tools like Figma and Notion alternatives.
Operational Transformation (OT), the older approach used by Google Docs, requires a central server to serialize operations and maintain transformation functions. CRDTs have largely displaced OT for new implementations because they work peer-to-peer and handle offline-first scenarios natively. As local-first architectures quietly winning against centralized cloud services demonstrate, the operational simplicity of CRDTs outweighs their memory overhead for most modern applications.
Real-World Battle Scars
The theory translates to production in unexpected ways.
DayTrak (Browser-First)
A time and money tracker running entirely in the browser, uses Evolu, a local-first framework combining SQLite (via WebAssembly), Kysely query builder, and CRDTs. Data lives in IndexedDB, queries run locally, and multi-device sync happens via end-to-end encrypted CRDTs with a 24-word recovery phrase. The relay server sees only encrypted blobs, it cannot read user data.
Ditto (Industrial Scale)
Takes this to industrial scale, embedding a local-first database on mobile devices that forms ad-hoc mesh networks via Bluetooth, Wi-Fi, or LAN. Used by the U.S. Air Force and Lufthansa for mission-critical systems in disconnected environments, Ditto leverages CRDTs to eliminate custom networking code while maintaining consistency across edge devices.
AFFiNE (Consumer Shift)
Represents the consumer-facing shift, local-first self-hosted workspaces that store data on-device using CRDTs for synchronization, challenging Notion’s cloud-only model. Users report dramatically faster search and navigation compared to Electron-based alternatives, with the added benefit of data remaining accessible during internet outages.
Manyana (Version Control)
A prototype by BitTorrent creator Bram Cohen, applies CRDTs to code collaboration. Unlike Git’s three-way merge that produces “opaque blobs” of conflict markers, Manyana’s CRDT-based system tracks what each side actually did, presenting conflicts informatively rather than as raw text diffs. Merges never fail by definition, the algorithm automatically determines the correct result.
When to Stay Cloud-First (and When to Escape)
Local-first is not a universal solution. CRDTs provide strong eventual consistency, not strong consistency. This distinction matters when building financial transaction systems or inventory management where two users cannot simultaneously “claim” the same resource. For these scenarios, the server must remain the coordination point.
However, for user-generated content, note-taking apps, design tools, project management, personal databases, local analytics outperforming cloud platforms on cost and speed is just the beginning. The paradigm eliminates API latency for reads, removes loading states, and reduces server costs dramatically because the server only handles sync and backup, not processing every request.
The tooling has matured to the point where you don’t need a PhD in distributed systems. PowerSync and ElectricSQL provide sync engines over existing Postgres databases. Zero and Triplit offer full-stack local-first frameworks. Automerge handles complex nested JSON documents with undo/redo support, while Yjs dominates text editing scenarios.
The New Default
The shift is subtle but profound: the default assumption in web development is changing from “data lives on the server, the client requests it” to “data lives on the client, the server helps distribute it.” This inversion eliminates the need for skeleton screens, optimistic updates, and background prefetching, workarounds for the fundamental latency of client-server architecture.
When building these systems, remember the hard-won lessons: handle schema changes carefully since migrations run on every client device, not just the server. Think about authorization differently, the sync layer controls which data subsets reach which clients, rather than checking permissions on every request. And consider security considerations when pushing computation to the edge, especially when dealing with sensitive financial or personal data.
The backend isn’t dead, but it is optional. For applications where user data belongs conceptually to the user, not to the platform, local-first architectures offer a path toward genuine data ownership, offline resilience, and collaborative capabilities that don’t evaporate when the internet does. The cloud becomes a convenience, not a dependency. And that’s a architecture worth building.



