Introduction to Loro
It is well-known that syncing data/building realtime collaborative apps is challenging, especially when devices can be offline or part of a peer-to-peer network. Loro simplifies this process for you.
We want to provide better DevTools to make building local-first apps (opens in a new tab) easy and enjoyable.
Loro uses Conflict-free Replicated Data Types (CRDTs) to resolve parallel edits. By utilizing Loro's data types, your applications can be made collaborative and keep the editing history with low overhead.
After you model your app state by Loro, syncing is simple:
const docA = new LoroDoc();
const docB = new LoroDoc();
docA.getText("text").insert(0, "Hello world!");
docB.getText("text").insert(0, "Hi!");
// Assume docA and docB are two Loro documents in two different devices
const bytesA = docA.export({ mode: "update" });
// send bytes to docB by any method
docB.import(bytesA);
// docB is now updated with all the changes from docA
const bytesB = docB.export({ mode: "update" });
// send bytes to docA by any method
docA.import(bytesB);
// docA and docB are now in sync, they have the same state
Saving your app state is also straightforward:
const doc = new LoroDoc();
doc.getText("text").insert(0, "Hello world!");
const bytes = doc.export({ mode: "snapshot" });
// Bytes can be saved to local storage, database, or sent over the network
Loading your app state:
const newDoc = new LoroDoc();
newDoc.import(bytes);
Loro also makes it easy for you to time travel the history and add version control to your app. Learn more about time travel.
doc.checkout(version); // Checkout the doc to the given version
Loro is compatible with the JSON schema. If you can model your app state with JSON, you probably can sync your app with Loro. Because we need to adhere to the JSON schema, using a number as a key in a Map is not permitted, and cyclic links should be avoided.
doc.toJSON(); // Get the JSON representation of the doc
Differences from other CRDT libraries
The table below summarizes Loro's features, which may not be present in other CRDT libraries.
Features/Important design decisions | Loro | Diamond-types | Yjs | Automerge |
---|---|---|---|---|
Event Graph Walker (opens in a new tab) | ✅ | ✅ Inventor | ❌ | ❌ |
Peritext (opens in a new tab) Rich Text CRDT | ✅[1] | ❌ | ❌ | ✅ Inventor |
Movable Tree (opens in a new tab) | ✅ | ❌ | ❌ | ❌ Inventor |
Movable List (opens in a new tab) | ✅ | ❌ | ❌ | ❌ Inventor |
Time Travel | ✅ | ✅ | ✅[2] | ✅ |
Fugue (opens in a new tab) / Maximal non-interleaving | ✅ | ✅ | ❌ | ❌ |
JSON Types | ✅ | ❓ | ✅ | ✅ |
Merging Elements in Memory by Run Length Encoding | ✅ | ✅ | ✅ Inventor | ❌ |
Byzantine-fault-tolerance | ❌ | ❌ | ❌ | ✅ |
Version Control | ✅ | ❌ | ❌ | ✅ |
- [1] Loro uses a Peritext-like algorithm to merge the concurrent edits to rich text styles. It's different from the original design but it passes all the criteria listed in the paper.
- [2] Unlike others, Yjs requires users to store a version vector and a delete set, enabling time travel back to a specific point.
- Fugue (opens in a new tab) is a text/list CRDTs that can minimize the chance of the interleaving anomalies.