# How the Docs Module Implements Real-Time Collaboration with Loro CRDTs and their‑mirror

> Explore Macro Docs real-time collaboration powered by Loro CRDTs and their-mirror. Learn how conflict-free editing is achieved through efficient sync services.

- Repository: [Macro/macro](https://github.com/macro-inc/macro)
- Tags: internals
- Published: 2026-08-20

---

**The Macro Docs product delivers instant, conflict‑free collaboration by storing each document in a Loro CRDT object (via the their‑mirror library) and syncing edits through a WebSocket‑connected sync‑service durable object.**

The Macro repository's docs module implements **conflict-free replicated data types (CRDTs)** to enable multiple users to edit documents simultaneously without locks or merge conflicts. According to the macro‑inc/macro source code, this architecture combines the **Loro CRDT engine**, a JavaScript bridge called **their‑mirror**, and a Rust‑powered **sync‑service** backend running on Cloudflare Workers.

## Core Architecture: Loro CRDT + their‑mirror

At the heart of the system is **Loro**, a high‑performance CRDT library written in Rust with JavaScript bindings. The Macro team built **their‑mirror** (`packages/loro‑mirror`) to create an ergonomic JavaScript API over raw Loro operations.

The `Mirror` class in `packages/loro‑mirror/src/core/mirror.ts` provides bidirectional synchronization between plain JavaScript state and a `Loro<Schema>` document:

- It tracks local mutations and translates them into Loro operations.
- It applies incoming remote operations to the local document.
- It exposes a reactive state object that UI components can read directly.

```typescript
import { Mirror } from '@macro-inc/loro-mirror';

const mirror = new Mirror({
  schema: MarkdownSchema,
  docId: 'doc-123',
  onUpdate: (updates) => ws.sendUpdates(updates),
});

```

The schema system in `packages/loro‑mirror/src/schema/index.ts` defines how JavaScript types map to Loro CRDT primitives:

| Schema Helper | Loro Type | Use Case |
|--------------|-----------|----------|
| `schema.text()` | `LoroText` | Rich text content, markdown |
| `schema.list(child)` | `LoroList` | Ordered collections (mentions, comments) |
| `schema.map(shape)` | `LoroMap` | Structured objects (metadata, attributes) |

## Connecting to the Sync‑Service

Real‑time synchronization happens through **sync‑service**, a Cloudflare Worker that hosts per‑document **Durable Objects**. Each document ID maps to exactly one durable object "room" that maintains the canonical CRDT state and broadcasts updates to all connected clients.

The client‑side connection is managed by `SyncServiceSource` in [`packages/collaboration/src/sync-service/source.ts`](https://github.com/macro-inc/macro/blob/main/packages/collaboration/src/sync-service/source.ts):

```typescript
import { createSyncClient } from '@macro-inc/collaboration/sync-service/socket';

const ws = createSyncClient(`wss://sync-service.example.com/document/${docId}`);

ws.onMessage((bebopEncodedUpdates) => {
  mirror.applyUpdates(bebopEncodedUpdates);
});

```

Key responsibilities of the sync‑service pipeline:

1. **WebSocket lifecycle**: Opens a persistent connection to the durable object.
2. **Bebop encoding**: All CRDT updates are serialized with Bebop for compact, fast binary transfer.
3. **Broadcast fan‑out**: When any peer sends an update, the durable object broadcasts it to all other sockets in the same room.

## The Collaboration Loop: How Edits Flow

The complete data flow for a real‑time edit follows this path:

```

┌─────────┐    local edit     ┌─────────┐    Loro op     ┌─────────────┐
│   UI    │ ─────────────────→│  Mirror │ ──────────────→│  WebSocket  │
└─────────┘                   └─────────┘                └──────┬──────┘
     ↑                                                          │
     └──────────────────────────────────────────────────────────┘
                            remote op (broadcast)

```

Step‑by‑step operation:

1. **User types** in the editor → UI calls `mirror.getState().body.insert(index, text)`.
2. **Mirror creates Loro operation** and invokes `onUpdate` callback.
3. **SyncServiceSource transmits** the Bebop‑encoded update to the durable object.
4. **Durable object broadcasts** to all connected clients (including the sender, for echo).
5. **Remote clients apply** updates via `mirror.applyUpdates()`, merging silently with any local edits.
6. **UI re‑renders** from `mirror.getState()`, now reflecting the merged state.

Because Loro CRDTs guarantee **strong eventual consistency**, concurrent edits from multiple users are automatically merged without conflicts—even if users go offline and reconnect later.

## Offline Support and Version Vectors

The their‑mirror architecture includes robust offline capabilities:

- **Local persistence**: Each client's `Mirror` can serialize its full document state (including version vector) to `IndexedDB` or local storage.
- **Incremental sync on reconnect**: When a client rejoins, it sends its version vector to the sync‑service durable object.
- **Delta encoding**: The server computes and sends only the operations the client missed, minimizing bandwidth.

This design ensures users can continue editing without network access and seamlessly sync when connectivity returns.

## Presence and Cursor Tracking

Beyond document content, the sync‑service protocol carries **presence metadata** for live collaboration indicators. The `Mirror` can expose peer cursor positions, selection ranges, and user awareness data that the UI renders as colored cursors or "user is editing" badges.

The protocol distinguishes **document operations** (CRDT updates) from **presence messages** (ephemeral state), routing each appropriately through the same WebSocket connection.

## Summary

- **Loro CRDT** (`packages/loro‑mirror`) provides the underlying merge‑free data structure for document state.
- **their‑mirror's `Mirror` class** (`packages/loro‑mirror/src/core/mirror.ts`) bridges idiomatic JavaScript APIs with Loro operations.
- **Schema definitions** (`packages/loro‑mirror/src/schema/index.ts`) type‑check document structures at runtime.
- **SyncServiceSource** ([`packages/collaboration/src/sync-service/source.ts`](https://github.com/macro-inc/macro/blob/main/packages/collaboration/src/sync-service/source.ts)) manages WebSocket transport and Bebop encoding.
- **Sync‑service durable objects** (`services/sync-service`) host per‑document rooms and broadcast updates.
- **Offline‑first design** with version vectors and delta sync ensures resilience.

## Frequently Asked Questions

### What is their‑mirror and why does Macro use it?

**their‑mirror is Macro's JavaScript abstraction layer over the Loro CRDT engine.** It provides a reactive, schema‑validated API that converts between plain JavaScript objects and Loro's internal operation log. Macro uses it to simplify UI integration while retaining Loro's performance and correctness guarantees.

### How does the sync‑service handle concurrent edits from dozens of users?

**Each document runs in its own Cloudflare Durable Object with single‑threaded execution.** All edits are serialized through this central point, then broadcast as CRDT operations that merge deterministically on each client. The Durable Object acts as a coordination hub without being a bottleneck—CRDT math happens on clients, not the server.

### Can users edit documents while offline?

**Yes—offline editing is a core feature.** Clients store their Loro document state locally with a version vector. On reconnection, they exchange version vectors with the sync‑service and receive only the operations they missed, merging them automatically with any edits made offline.

### What data format travels over the network?

**All updates use Bebop binary encoding.** This compact, schema‑driven format minimizes payload size compared to JSON. The `SyncServiceSource` class handles encoding/decoding transparently so application code works with JavaScript objects.