Loro (CRDT) Collaboration
Real-time collaboration using Loro CRDTs
Loro is a high-performance CRDT library that enables real-time collaboration with automatic conflict resolution. The @rowsncolumns/loro package provides a React hook for integrating Loro with your spreadsheet.
Installation
yarn add @rowsncolumns/loro loro-crdtnpm install @rowsncolumns/loro loro-crdtQuick Start
import { useLoro } from "@rowsncolumns/loro";
import { LoroDoc } from "loro-crdt";
// Create a Loro document
const loroDoc = new LoroDoc();
function SpreadsheetEditor() {
const [sheetData, setSheetData] = useState({});
const [sheets, setSheets] = useState([]);
const [tables, setTables] = useState([]);
const [sheetId, setSheetId] = useState(1);
const [activeCell, setActiveCell] = useState({ rowIndex: 1, columnIndex: 1 });
const { onBroadcastPatch, users, synced, isLeader, importUpdate } = useLoro({
doc: loroDoc,
userId: "user-123",
title: "John Doe",
sheetId,
activeCell,
initialSheets: [],
onChangeSheetData: setSheetData,
onChangeSheets: setSheets,
onChangeTables: setTables,
onChangeActiveSheet: setSheetId,
calculateNow,
enqueueGraphOperation: (op) => {
// Handle dependency graph updates for formula recalculation
},
onSyncUpdate: (update) => {
// Send update to server
websocket.send(update);
},
});
// Pass onBroadcastPatch to useSpreadsheetState
return <Spreadsheet sheetData={sheetData} sheets={sheets} users={users} />;
}Integration with useSpreadsheetState
Connect the Loro adapter to your spreadsheet state:
Setting Up a Loro Sync Server
Basic Server
Create a file server.ts:
Install dependencies:
Run the server:
Server with Redis Persistence
For production environments, persist Loro snapshots to Redis:
Server with PostgreSQL Persistence
Document Structure
The Loro document stores all spreadsheet data:
Cell Key Format
Cell keys follow the pattern ${sheetId}!${A1Address}:
"1!A1"
Cell A1 on sheet 1
"2!B5"
Cell B5 on sheet 2
"1!AA100"
Cell AA100 on sheet 1
CellDataV3 Structure
Each cell value is stored with its position metadata:
Presence Awareness
The hook automatically manages presence, allowing you to display other users' cursor positions:
Each user in the users array includes:
Leader Election
The adapter automatically elects a leader among connected clients. The leader is responsible for coordinating recalculation operations.
Offline Support
Loro CRDTs work fully offline. Changes are stored locally and automatically merged when reconnecting:
Error Handling
Handle errors with the onError callback:
Why Loro for Spreadsheets?
Loro's CRDT approach offers unique advantages for spreadsheet collaboration.
Comparison with ShareDB
Conflict Resolution
Automatic merge, eventual consistency
Server determines canonical order
Server Required
Optional (can sync peer-to-peer)
Yes
Offline Support
Full offline-first support
Requires server connection
Performance
Rust core compiled to WASM
Pure JavaScript
Recalculation
Leader election for coordination
Leader election for coordination
History
Built-in version history and time travel
Manual operation log
Data Persistence
Any storage (Redis, PostgreSQL, S3, etc.)
MongoDB, PostgreSQL via adapters
Why CRDTs Work Well for Spreadsheets
Cell-level granularity - The V3 flat map structure (
"sheetId!A1"keys) maps perfectly to Loro's Map CRDT. Each cell is independent, minimizing conflicts.Offline-first - Users can work without connectivity and sync later. All changes are preserved and merged automatically.
High performance - Loro's Rust core provides excellent performance for large documents and many concurrent operations.
Flexible architecture - No central server required. Can use WebSocket, WebRTC, or any transport.
Built-in history - Time travel and version history are built into the CRDT.
When to Choose Loro
Need offline-first capabilities
Want high-performance CRDT operations
Need flexible sync (WebSocket, WebRTC, etc.)
Decentralized architecture is preferred
Need built-in version history
When to Choose ShareDB
Need traditional client-server architecture
Want to leverage existing MongoDB/PostgreSQL infrastructure
Prefer OT semantics for conflict resolution
Need server-side authority for all operations
Last updated