35 releases (22 stable)
| new 1.10.3 | Dec 9, 2025 |
|---|---|
| 1.10.0 | Nov 27, 2025 |
| 1.8.1 | Sep 23, 2025 |
| 1.5.10 | Jul 22, 2025 |
| 0.1.0 | Aug 7, 2022 |
#65 in Network programming
2,731 downloads per month
Used in 5 crates
(4 directly)
2.5MB
59K
SLoC
Loro
Loro is a high‑performance CRDT framework for local‑first apps that keeps state consistent across devices and users, works offline and in real time, automatically merges conflicts, and enables undo/redo and time travel.
Loro is a high-performance CRDTs library offering Rust, JavaScript and Swift APIs.
Common Tasks & Examples
Getting Started
- Create a document:
LoroDoc::new()- Initialize a new collaborative document - Add containers:
get_text,get_list,get_map,get_tree,get_movable_list,get_counter(feature "counter") - Listen to changes:
subscribeorsubscribe_root- React to document/container modifications - Export/Import state:
exportandimport- Save and load documents
Real-time Collaboration
- Sync between peers:
export(ExportMode::updates(&vv))+import- Exchange incremental updates (seeExportMode::updates) - Stream updates:
subscribe_local_update- Send changes over WebSocket/WebRTC - Set unique peer ID:
set_peer_id- Ensure each client has a unique identifier - Handle conflicts: Automatic - All Loro data types are CRDTs that merge concurrent edits
Rich Text Editing
- Create rich text:
get_text- Initialize a collaborative text container - Edit text:
LoroText::insert,LoroText::delete,LoroText::apply_delta - Apply formatting:
LoroText::mark- Add bold, italic, links, custom styles - Track cursor positions:
LoroText::get_cursor+LoroDoc::get_cursor_pos- Stable positions across edits - Configure styles:
config_text_style/config_default_text_style- Define expand behavior for marks
Data Structures
- Ordered lists:
get_list- Arrays withpush,insert,delete - Key-value maps:
get_map- Objects withinsert,get,delete - Hierarchical trees:
get_tree- Trees withcreate,mov,mov_to - Reorderable lists:
get_movable_list- Drag-and-drop withmov,set - Counters:
get_counter(feature "counter") - Distributed counters withincrement
Ephemeral State & Presence
- Not currently provided in the Rust crate. Model presence in your app layer alongside CRDT updates (e.g., via your network transport). Cursors can be shared using
get_cursordata if needed.
Version Control & History
- Undo/redo:
UndoManager- Local undo of user’s own edits - Time travel:
checkoutto anyFrontiers- Debug or review history - Version tracking:
oplog_vv,state_frontiers,VersionVector - Fork documents:
forkorfork_at- Create branches for experimentation - Merge branches:
import- Combine changes from forked documents
Performance & Storage
- Incremental updates:
export(ExportMode::updates(&their_vv))- Send only changes (seeExportMode::updates) - Compact history:
export(ExportMode::Snapshot)- Full state with compressed history (seeExportMode::Snapshot) - Shallow snapshots:
export(ExportMode::shallow_snapshot(&frontiers))- State without partial history (seeExportMode::shallow_snapshot)
Documentation
- Start with the Rust API docs for
LoroDoc(container management, versioning, import/export, events) That page hosts examples and details for most important methods you’ll use day-to-day. - Loro Website for more details and guides
- Loro Examples for more examples and guides
Getting Started
Add to your Cargo.toml:
[dependencies]
loro = "^1"
LoroDoc quick tour
- Containers:
get_text,get_map,get_list,get_movable_list,get_tree - Import/Export:
export(ExportMode::…),import,from_snapshot - Versioning:
oplog_vv,state_frontiers,checkout/checkout_to_latest,revert_to,fork - Events:
subscribe,subscribe_root,subscribe_local_update(send deltas to peers) - Paths/JSON:
get_path_to_container,get_deep_value/ToJson(to_json_value()), optionaljsonpath(feature)
Optional cargo features:
[dependencies]
loro = { version = "^1", features = ["jsonpath"] }
Quick Examples
- Local edits, change events, and two-peer sync
use loro::{LoroDoc, ExportMode};
use std::sync::Arc;
let a = LoroDoc::new();
let b = LoroDoc::new();
// Listen for container diffs on `a`
let _changes = a.subscribe_root(Arc::new(|e| {
println!("changed containers: {}", e.events.len());
}));
a.get_text("text").insert(0, "Hello, Loro!").unwrap();
a.commit(); // events fire on commit/export/import/checkout
// Sync via export/import (send `updates` via your transport)
let updates = a.export(ExportMode::all_updates()).unwrap();
b.import(&updates).unwrap();
assert_eq!(a.get_deep_value(), b.get_deep_value());
- Time travel and revert
use loro::LoroDoc;
let doc = LoroDoc::new();
let text = doc.get_text("text");
text.insert(0, "Hello").unwrap();
let v0 = doc.state_frontiers();
text.insert(5, ", world").unwrap();
assert_eq!(text.to_string(), "Hello, world");
// Time travel to v0 (read-only)
doc.checkout(&v0).unwrap();
assert_eq!(text.to_string(), "Hello");
// Return to latest and revert
doc.checkout_to_latest();
doc.revert_to(&v0).unwrap();
assert_eq!(text.to_string(), "Hello");
Dependencies
~9–29MB
~510K SLoC