Skip to content

Commit fcf7afe

Browse files
authored
Blog: loro-protocol (#31)
* Blog: loro-protocol * Add cover
1 parent 756ab28 commit fcf7afe

File tree

3 files changed

+124
-0
lines changed

3 files changed

+124
-0
lines changed

pages/blog/_meta.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
export default {
2+
"loro-protocol": {
3+
theme: {
4+
toc: true,
5+
pagination: false,
6+
},
7+
},
28
"loro-mirror": {
39
theme: {
410
toc: true,

pages/blog/loro-protocol.mdx

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
---
2+
title: "Loro Protocol"
3+
date: 2025/10/30
4+
description: "The Loro Protocol multiplexes CRDT sync workloads over one WebSocket connection with adaptors for Loro documents, EphemeralStore, and Yjs interoperability."
5+
image: "/images/blog-loro-protocol.png"
6+
---
7+
8+
## Loro Protocol
9+
10+
import Authors, { Author } from "../../components/authors";
11+
12+
<Authors date="2025-10-30">
13+
<Author name="Zixuan Chen" link="https://www.loro.dev/" />
14+
</Authors>
15+
16+
![](/images/blog-loro-protocol.png)
17+
18+
The [**Loro Protocol**](https://github.com/loro-dev/protocol) is a wire protocol designed for real-time CRDT synchronization. Learn about the design in detail [here](https://github.com/loro-dev/protocol/blob/main/protocol.md).
19+
20+
It efficiently runs multiple, independent "rooms" over a single WebSocket connection.
21+
22+
This allows you to synchronize your application state, such as a Loro document, ephemeral cursor positions, and end-to-end encrypted documents, over one connection. It is also compatible with Yjs.
23+
24+
### Quick Start: Server & Client Example
25+
26+
The protocol is implemented by the `loro-websocket` client and a minimal `SimpleServer` for testing. These components are bridged to your CRDT state using `loro-adaptors`.
27+
28+
**Server**
29+
30+
For development, you can run the `SimpleServer` (from `loro-websocket`) in a Node.js environment.
31+
32+
```tsx
33+
// server.ts
34+
import { SimpleServer } from "loro-websocket/server";
35+
36+
const server = new SimpleServer({
37+
port: 8787,
38+
// SimpleServer accepts hooks for authentication and data persistence:
39+
// authenticate: async (roomId, crdt, auth) => { ... },
40+
// onLoadDocument: async (roomId, crdt) => { ... },
41+
// onSaveDocument: async (roomId, crdt, data) => { ... },
42+
});
43+
44+
server.start().then(() => {
45+
console.log("SimpleServer listening on ws://localhost:8787");
46+
});
47+
```
48+
49+
**Client**
50+
51+
On the client side, you connect once and then join multiple rooms using different adaptors.
52+
53+
```tsx
54+
// client.ts
55+
import { LoroWebsocketClient } from "loro-websocket";
56+
import { LoroAdaptor, LoroEphemeralAdaptor } from "loro-adaptors";
57+
58+
// 1. Create and connect the client
59+
const client = new LoroWebsocketClient({ url: "ws://localhost:8787" });
60+
await client.waitConnected();
61+
console.log("Client connected!");
62+
63+
// --- Room 1: A Loro Document (%LOR) ---
64+
const docAdaptor = new LoroAdaptor();
65+
const docRoom = await client.join({
66+
roomId: "doc:123",
67+
crdtAdaptor: docAdaptor,
68+
});
69+
70+
// Local edits are now automatically synced
71+
const text = docAdaptor.getDoc().getText("content");
72+
text.insert(0, "Hello, Loro!");
73+
docAdaptor.getDoc().commit();
74+
75+
// --- Room 2: Ephemeral Presence (%EPH) on the SAME socket ---
76+
const ephAdaptor = new LoroEphemeralAdaptor();
77+
const presenceRoom = await client.join({
78+
roomId: "doc:123", // Can be the same room ID, but different magic bytes
79+
crdtAdaptor: ephAdaptor,
80+
});
81+
82+
// Ephemeral state syncs, but is not persisted by the server
83+
ephAdaptor.getStore().set("cursor", { x: 100, y: 100 });
84+
```
85+
86+
---
87+
88+
### Key Protocol Features
89+
90+
#### Multiplexing
91+
92+
Each binary message is prefixed with four magic bytes that identify the data type, followed by the `roomId`. This structure allows the server to route messages to the correct handler. A single client can join:
93+
94+
- `%LOR` (Loro Document)
95+
- `%EPH` (Loro Ephemeral Store, for cursors and presence)
96+
- `%ELO` (End-to-End Encrypted Loro Document)
97+
- `%YJS` and `%YAW` (for Yjs Document and Awareness interoperability)
98+
99+
All traffic runs on the same socket.
100+
101+
#### Compatibility
102+
103+
The Loro Protocol is designed to accommodate environments like Cloudflare:
104+
105+
- Fragmentation: Large updates are automatically split into fragments under 256 KiB and reassembled by the receiver. This addresses platforms that enforce WebSocket message size limits.
106+
- Application-level keepalive: The protocol defines simple `"ping"` and `"pong"` text frames. These bypass the binary envelope and allow the client to check connection liveness, which is useful in browser or serverless environments where transport-level TCP keepalives are not exposed.
107+
108+
This repository also ships Rust clients and servers that mirror the TypeScript packages.
109+
110+
### Experimental E2E Encryption
111+
112+
End-to-end encrypted Loro is included in `loro-protocol`, but the feature is currently experimental: expect wire formats and key-management APIs to change, and do not rely on it for production-grade security audits yet. When paired with `EloLoroAdaptor` on the client, the server relays encrypted records without decrypting them.
113+
114+
### Status and Licensing
115+
116+
The Loro Protocol is mostly stable. We welcome community feedback and contributions, especially regarding use cases that are difficult to satisfy with the current design.
117+
118+
All the packages in inside https://github.com/loro-dev/protocol are open-sourced under the permissive MIT license.
2.93 MB
Loading

0 commit comments

Comments
 (0)