loro-crdt
v1.13.6
Published
Loro CRDTs is a high-performance CRDT framework that makes your app state synchronized, collaborative and maintainable effortlessly.
Readme
Loro is a CRDTs(Conflict-free Replicated Data Types) library that makes building local-first and collaborative apps easier. You can now use it in Rust, JS (via WASM), and Swift.
Features
Features Provided by CRDTs
- P2P Synchronization
- Automatic Merging
- Local Availability
- Scalability
- Delta Updates
Supported CRDT Algorithms
- 📝 Text Editing with Fugue
- 📙 Rich Text CRDT
- 🌲 Moveable Tree
- 🚗 Moveable List
- 🗺️ Last-Write-Wins Map
- 🤝 Mergeable map-key children via
ensureMergeable*for lazy child container creation
Advanced Features in Loro
- 🚀 Fast Document Loading
- ⏱️ Fast Time Travel Through History
- 🏛️ Version Control with Real-Time Collaboration
- 📦 Shallow Snapshot that Works like Git Shallow Clone
In this example, we demonstrate importing an entire Loro codebase into a Loro-powered version controller, preserving the complete Git DAG history while enabling fast version switching.
Debugging the Wasm build
The standard build pipeline (deno run -A ./scripts/build.ts dev|release) now keeps DWARF debugging information through wasm-bindgen and emits two helper files alongside every loro_wasm_bg.wasm artifact:
loro_wasm_bg.wasm.map— a v3 source map derived from DWARF so that Chrome, Edge, and Firefox can show original Rust locations when inspecting stack traces.
Load the source map in browser devtools; when devtools fetches the debug companion it can map instructions back to Rust source files and line numbers without inflating the shipped .wasm.
Bundler entries
Bare import { LoroDoc } from "loro-crdt" uses package conditional exports. Browser development builds can resolve the nested browser + development conditions to the bundler entry, while browser production builds can resolve the browser condition to a synchronous browser build that avoids Vite/Rolldown production chunk cycles around .wasm wrappers. A legacy browser string field also points to the browser entry for bundlers that still consult it. Runtimes that need native .wasm module imports can still use the bundler entry, and apps that prefer explicit async initialization can use loro-crdt/web.
Vite and Webpack understand new URL("./loro_wasm_bg.wasm", import.meta.url) and emit the WASM asset automatically. Plain esbuild and plain Rollup do not copy that asset by default. For those tools, either import loro-crdt/base64 to inline the WASM into the JS bundle without top-level await, or keep the default loro-crdt import and copy node_modules/loro-crdt/browser/loro_wasm_bg.wasm next to the emitted JS bundle as a build step.
Next.js Turbopack can use the default browser entry. If a Next.js Webpack build resolves the bundler entry instead of the package browser remap, use loro-crdt/base64.
Example
import { expect, test } from 'vitest';
import { LoroDoc, LoroList } from 'loro-crdt';
test('sync example', () => {
// Sync two docs with two rounds of exchanges
// Initialize document A
const docA = new LoroDoc();
const listA: LoroList = docA.getList('list');
listA.insert(0, 'A');
listA.insert(1, 'B');
listA.insert(2, 'C');
// Export all updates from docA
const bytes: Uint8Array = docA.export({ mode: 'update' });
// Simulate sending `bytes` across the network to another peer, B
const docB = new LoroDoc();
// Peer B imports the updates from A
docB.import(bytes);
// B's state matches A's state
expect(docB.toJSON()).toStrictEqual({
list: ['A', 'B', 'C'],
});
// Get the current version of docB
const version = docB.oplogVersion();
// Simulate editing at B: delete item 'B'
const listB: LoroList = docB.getList('list');
listB.delete(1, 1);
// Export the updates from B since the last sync point
const bytesB: Uint8Array = docB.export({ mode: 'update', from: version });
// Simulate sending `bytesB` back across the network to A
// A imports the updates from B
docA.import(bytesB);
// A has the same state as B
expect(docA.toJSON()).toStrictEqual({
list: ['A', 'C'],
});
});Blog
- Loro 1.0
- Movable tree CRDTs and Loro's implementation
- Introduction to Loro's Rich Text CRDT
- Loro: Reimagine State Management with CRDTs
Credits
Loro draws inspiration from the innovative work of the following projects and individuals:
- Diamond-types: The Event Graph Walker (Eg-walker) algorithm from @josephg has been adapted to reduce the computation and space usage of CRDTs.
- Automerge: Their use of columnar encoding for CRDTs has informed our strategies for efficient data encoding.
- Yjs: We have incorporated a similar algorithm for effectively merging collaborative editing operations, thanks to their pioneering work.
- Matthew Weidner: His work on the Fugue algorithm has been invaluable, enhancing our text editing capabilities.
- Martin Kleppmann: His work on CRDTs has significantly influenced our comprehension of the field.
