In my previous article, I provided a broad explanation of the algorithms that allow local-first applications to synchronize data correctly using CRDTs (Conflict-free Replicated Data Types).
When you see a local-first app that seamlessly syncs with other applications distributed worldwide, it feels like magic. Under the hood, a lot is happening, and it has to happen in the right order for the algorithm to preserve correctness..
The source code of this simple iOS and Android ToDo app can be found at: https://github.com/sqliteai/sqlite-sync/tree/main/examples/to-do-app
Let’s look more deeply at what really happens when a value in a local-first app (backed by SQLite) is INSERTed, UPDATEd, or DELETEd.
Initial setup
Suppose we have two users, Bob and Alice, each with a local SQLite database named todo.sqlite that contains the following table:
CREATE TABLE todo ( id TEXT PRIMARY KEY NOT NULL, title TEXT, status TEXT );
Initially, both databases are empty, and at some point, Alice adds a "Buy groceries" item to the todo table with status set to "in_progress". In SQL it can be translated to:
INSERT INTO todo (id, title, status) VALUES ('ID1', 'Buy groceries', 'in_progress');
At the SQL level, this is just a row insert. But for the sync engine, this single INSERT is not enough information to replicate the change safely across peers. It needs to break the change apart and record causality.
... continue reading