tags : Human Computer Interaction ( HCI ), peer-to-peer, Alternative Internet, WebAssembly, Synchronization

I like how Kyle Mathews describes local first software, most of this doc is extracting things out of his blogpost:

“local-first” as shifting reads and writes to an embedded database in each client via“sync engines” that facilitate data exchange between clients and servers.

Useful for applications that demand stuff to be either of but not limited to real-time, collaborative(multiplayer), or offline.

Did people have to be online to collaborate online? Or could they work offline and collaborate peer-to-peer?

Ecosystem concepts

Sync Engines

See Synchronization

Distributed state machine / Replicated state machine (RSM) / State machine replication

  • Towards “Handle writes that need an authoritative server”
  • By emulating API request/response patterns through: A distributed state machine running on a replicated object.
  • i.e we write interactions w external services in a way so that requests/responses have the same multiplayer, offline, real-time sync properties as the rest of the app.
  • This synchronization can be at the application, network or other levels of the stack

2 Primary idea that makes synchronization easy

  • A reliable, ordered message stream: Every machine in the system sees the messages in the same order.
  • A fully-deterministic compute environment: Given the same inputs always result in the same outputs

Partially replication

  • Query-based sync to partially replicate

UI/UX ecosystem around local first

Personal & Local software

See Software Possession for Personal Use | olano.dev

Basics

Architecture for LoFi

  • Instead of always assuming that the server is the authortative source, we assumed that the user’s local device is the authoritative source of information
  • The default consistency mode is Eventual Consistency
    • This means that state and compute can naturally exist at the edge
    • Only brought to the “center” when there is a need for strong consistency

Challenges

From Why SQLite? Why Now? 🐇 - Tantamanlands

  • How much data can you store locally?
  • How do you signal to the user that their local set of data could be incomplete from the perspective of other peers?
  • How do we bless certain peers (or servers) as authoritative sources of certain sets of information?
  • What CRDTs are right for which use cases?

Approaches

Categorization

Replicated protocols

  • This is what Replicache currently does, client JS library along with a replication protocol.

Replicated Data Structures

  • Building block Data Structures
  • Provide APIs similar to native Javascript maps and arrays but guarantees state updates are replicated to other clients and to the server.
  • Most replicated data structures rely on crdt algorithms to merge concurrent and offline edits from multiple clients.
  • If not a replicated data structure, we’d have to pass that info though websockets/requests/messaging services etc manually.

Replicated Database

  • Write to your database while offline. I can write to mine while offline. We can then both come online and merge our databases together, without conflict. See Data Replication.
  • Some of these just do syncing, some do partial sync, some do client side storage as-well etc. It’s a mixed bag.

Offline/Browser only database

In this architecture you basically don’t really do sync but just use a WebAssembly browser (duckdb, sqlite, pglite etc) but don’t sync back. This is more like local-only instead of local first. See this for an example.

Tools/Implementations

CategoryTool NameType / Sub-categoryDescription/NotesInteresting?
Replicated ProtocolsReplicacheServiceClient JS library and replication protocol. Sync engine requires some setup (“some assembly required”).
Replicated Data StructuresYjsOSSRelies on CRDTs to merge concurrent/offline edits. Provides APIs similar to native JS maps/arrays.
AutomergeOSSRelies on CRDTs. Allows sync across devices + local persistence with minimal code changes in React apps.
jazzOSSDescribed as a replicated data structure.
LiveblocksServiceListed as a service providing replicated data structures.
PartykitServiceListed as a service providing replicated data structures.
off-the-shelfInstantDBOthermodern Firebase. See explanation., inspired by Clojure and Datomic🌟
ElectricSQLPostgres-SQLiteReplicates writes from PostgreSQL to client-side SQLite. Supports write-back and partial replication.🌟
PowerSyncPostgres-SQLiteReplicates writes from databases (incl. PostgreSQL) to client-side SQLite. Supports write-back, partial replication, sync from multiple DBs.
tinybaseOtherthe main dev has a yatch. Here are some slides
rxdbOtherI find rxdb to look visually similar to tinybase
zerosyncOther
DittoServicedatabase with edge device connectivity and resiliency, synchronize without relying on a central server, so crdt + peer-to-peer🌟
Google FirebaseServiceGoogle offers two realtime databases under the Firebase brand. Cloud Firestore and Firebase Realtime Database.
couchdb and pouchdbCouchdb is a database based around replication. Pouchdb offers an in-browser database with server replication, and did so before it was cool.
aws app-sync
Replicated Database
sqledgePostgres-SQLiteSync engine possibly for readonly replication from Postgres. From the creators of Ably.
cr-sqliteSQLite-SQLiteCRDT-based replication between SQLite instances.🌟
sqlsyncSQLite-SQLiteProvides a custom storage layer for SQLite sync. Original version supported full DB sync only with a simpler engine.
graftSQLite-SQLiteFrom the same team as sqlsync; allows partial sync/replication. Check this thread which discusses the consistency model🌟
MycelialSQLite-SQLitePlatform for replicating SQLite databases.
EvoluOther (SQLite/OPFS)Seems to use SQLite on top of OPFS (Origin Private File System) for replication.
TriplitOther (IndexedDB)Uses IndexedDB for storage and replication. Also listed initially as a Replicated Data Structure service.
Offline/Browser Only DBduckdbBrowser DB (Wasm)Example of a WebAssembly database for browser use, typically local-only without sync-back in this context.
sqliteBrowser DB (Wasm)Example of a WebAssembly database (like DuckDB) for browser-only use.
pgliteBrowser DB (Wasm)Example of a WebAssembly database (like DuckDB/SQLite) for browser-only use.

War stories

HN Comment 1

  • Initially we tried to use IndexDB to give us more of the local-first features by caching between loads, but it was more hassle than it was worth.
  • Instead we settled on live queries using Hasrua (we were a very early user / paying customer). We preload all the data that the user is going to need on app boot and then selectively load large chunks as they open their projects. These are then keeping mobx models up to date.
  • For mutating data we have a simple transaction system that you wrap around models to update them. It records and sends the mutations and makes sure that outstanding mutations are replayed over model changes locally.

Others

  • Offline support just kinda happened for free. Once I added a service worker to serve the app code offline, Automerge can just persist writes to local IndexedDB and then sync when network is back again, not a big deal. Classic local-first win

Community

Tools