# How Macro Implements CRDT-Based Real-Time Collaboration for Docs

> Discover how Macro implements CRDT-based real-time collaboration for docs using loro-crdt. Experience seamless distributed editing with automatic conflict resolution.

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

---

**Macro's Docs feature achieves real-time collaborative editing through a Conflict-Free Replicated Data Type (CRDT) engine powered by the open-source loro-crdt library, enabling automatic conflict resolution across distributed peers without custom merge logic.**

The macro-inc/macro repository contains a production-grade implementation of this architecture within the `@macro-inc/collaboration` TypeScript package. This system enables Google Docs-style simultaneous editing by embedding all document state—including text content, metadata, and cursor positions—inside immutable CRDT structures that guarantee eventual consistency.

## CRDT-Based Real-Time Collaboration Architecture

Macro's collaboration system consists of five tightly-coupled layers that handle everything from low-level data structures to UI integration.

### CRDT Core with loro-crdt

At the foundation lies the **loro-crdt** library, which provides immutable data structures including text, maps, lists, and movable lists. The web client imports these primitives directly:

```typescript
import { LoroDoc, UndoManager, Cursor } from 'loro-crdt';

```

As seen in [`apps/web/src/lib/core/component/LexicalMarkdown/collaboration/undo.ts`](https://github.com/macro-inc/macro/blob/main/apps/web/src/lib/core/component/LexicalMarkdown/collaboration/undo.ts), these types enable automatic conflict resolution without manual intervention.

### Collaboration Package

The `@macro-inc/collaboration` package wraps the core CRDT functionality within a higher-level API. The central component is the **`LoroManager`**, instantiated in [`packages/collaboration/src/collab/engine.ts`](https://github.com/macro-inc/macro/blob/main/packages/collaboration/src/collab/engine.ts). This manager tracks the document state, user awareness (presence and cursors), and persistence mechanisms.

The engine creates a `LoroDoc` instance, attaches an `Awareness` object, and wires the document to a Write-Ahead-Log (WAL) based SyncSource for backend communication.

### Write-Ahead-Log Sync Source

The **`createWALSyncSource`** function in [`packages/collaboration/src/collab/wal.ts`](https://github.com/macro-inc/macro/blob/main/packages/collaboration/src/collab/wal.ts) serializes CRDT updates to Macro's backend Sync Service. This WAL-based approach guarantees ordering and durability across Cloudflare Durable Objects. The UI layer consumes this through components like [`apps/web/src/features/block-md/component/MarkdownCollabProvider.tsx`](https://github.com/macro-inc/macro/blob/main/apps/web/src/features/block-md/component/MarkdownCollabProvider.tsx).

### Awareness Layer

Peer presence—including cursor positions, text selections, and user metadata (names, avatars)—is handled by the **Awareness** system implemented in [`packages/collaboration/src/collab/awareness.ts`](https://github.com/macro-inc/macro/blob/main/packages/collaboration/src/collab/awareness.ts). This layer leverages `loro-crdt`'s built-in `Cursor` type to propagate presence information through the same CRDT channel as document edits, ensuring all clients maintain a consistent view of participants.

### Sync Service Backend

The lightweight Sync Service, located in `services/sync-service/src/`, stores WAL entries and broadcasts them to connected peers via WebSocket connections. It provides snapshot endpoints (`/snapshot/:docId`) that allow new collaborators to load the current document state instantly without replaying the entire operation history.

## How Real-Time Collaboration Works in Practice

The collaboration flow follows six distinct stages from document creation to remote synchronization:

1. **Document initialization** – When a user opens a document, the UI creates a fresh `LoroDoc` instance and registers it with a `LoroManager`. In [`apps/web/src/features/block-md/history/HistoryContext.tsx`](https://github.com/macro-inc/macro/blob/main/apps/web/src/features/block-md/history/HistoryContext.tsx), this appears as:

```typescript
const doc = new LoroDoc();
const manager = new LoroManager(doc);

```

2. **Local edit capture** – The Lexical editor emits text changes that translate into `LoroDoc` updates, such as `doc.getText('content').insert(...)`. The CRDT automatically handles concurrent edits from multiple users without custom merge logic.

3. **Awareness propagation** – Each peer creates an `Awareness` object via `createAwareness` that tracks cursor position and selection. When users move their cursors, awareness updates store within the same CRDT, allowing every client to render remote cursors accurately.

4. **WAL persistence** – The `createWALSyncSource` function writes every CRDT update to the Sync Service's write-ahead log. The service stores these entries in Cloudflare Durable Objects and optionally in Postgres for long-term snapshots.

5. **Broadcast to peers** – The Sync Service pushes logged updates through WebSocket connections. The client's `SyncEngine` receives binary updates and feeds them back into the local `LoroDoc`, causing the UI to automatically reflect remote changes.

6. **Snapshot loading** – New collaborators fetch the latest snapshot from `/snapshot/:docId` (handled by `services/sync-service/src/`), receiving the full CRDT state to start editing immediately without operational lag.

## Implementation Code Examples

Creating a Loro document with full collaboration support follows this pattern:

```typescript
import { LoroDoc } from 'loro-crdt';
import { LoroManager } from '@macro-inc/collaboration/collab/manager';
import { createAwareness } from '@macro-inc/collaboration/collab/awareness';
import { createWALSyncSource } from '@macro-inc/collaboration/collab/wal';

const loro = new LoroDoc();
const awareness = createAwareness(loro);
awareness.setLocalState({ userId: currentUser.id, name: currentUser.name });

const manager = new LoroManager(loro, awareness);

const syncSource = createWALSyncSource({
  docId: currentDoc.id,
  manager,
  websocketUrl: `wss://sync.macro.com/${currentDoc.id}`,
});

```

React components consume the manager through hooks:

```tsx
import { useEffect } from 'react';
import { useLoroManager } from '@macro-inc/collaboration/react';

export function MarkdownEditor({ docId }: { docId: string }) {
  const { manager } = useLoroManager(docId);

  useEffect(() => {
    const unsub = manager.awareness.on('update', () => {
      // Re-render remote cursors
    });
    return unsub;
  }, [manager]);

  return <LexicalEditor text={manager.doc.getText('content')} />;
}

```

## Key Source Files

- **[`packages/collaboration/src/collab/engine.ts`](https://github.com/macro-inc/macro/blob/main/packages/collaboration/src/collab/engine.ts)** – Core engine creating the `LoroDoc`, attaching awareness, and exposing the sync API.
- **[`packages/collaboration/src/collab/awareness.ts`](https://github.com/macro-inc/macro/blob/main/packages/collaboration/src/collab/awareness.ts)** – Implements peer-presence using `loro-crdt`'s `Cursor` type.
- **[`packages/collaboration/src/collab/wal.ts`](https://github.com/macro-inc/macro/blob/main/packages/collaboration/src/collab/wal.ts)** – Write-Ahead-Log sync source serializing CRDT updates to the backend.
- **`services/sync-service/src/`** – Backend service storing WAL entries and streaming updates via WebSocket.
- **[`apps/web/src/features/block-md/component/MarkdownCollabProvider.tsx`](https://github.com/macro-inc/macro/blob/main/apps/web/src/features/block-md/component/MarkdownCollabProvider.tsx)** – UI glue building the `LoroManager` and wiring sync sources.
- **[`apps/web/src/lib/core/component/LexicalMarkdown/collaboration/undo.ts`](https://github.com/macro-inc/macro/blob/main/apps/web/src/lib/core/component/LexicalMarkdown/collaboration/undo.ts)** – Demonstrates `UndoManager` from `loro-crdt` for collaborative undo/redo.

## Summary

- Macro's Docs feature uses the **loro-crdt** library to power its CRDT-based real-time collaboration engine through the `@macro-inc/collaboration` package.
- The **`LoroManager`** unifies document state, user awareness, and persistence in a single abstraction layer.
- **Write-Ahead-Log synchronization** ensures durable, ordered updates across Cloudflare Durable Objects and Postgres snapshots.
- All state—including text content and cursor positions—lives inside the CRDT, eliminating custom merge code and guaranteeing eventual consistency.
- New peers load **snapshots** instantly via dedicated endpoints, enabling immediate participation without operational replay.

## Frequently Asked Questions

### How does Macro handle concurrent edits from multiple users?

Macro delegates conflict resolution entirely to the `loro-crdt` library. When concurrent edits occur, the CRDT's built-in algorithms automatically merge changes based on operational semantics. Because all state (text, maps, lists) exists within the `LoroDoc`, the system achieves convergence without requiring custom merge logic or server-side coordination.

### What happens when a new user joins a document mid-session?

The new collaborator fetches a snapshot from the Sync Service endpoint `/snapshot/:docId`, implemented in `services/sync-service/src/`. This snapshot contains the full CRDT state rather than a history of operations, allowing the newcomer to initialize their `LoroDoc` with the current document instantly. Subsequent real-time updates arrive via WebSocket from the write-ahead log.

### Does the collaboration system support offline editing?

Yes. Because `loro-crdt` operates as a local-first data structure, users can continue editing offline with their local `LoroDoc` instance. When connectivity returns, the `createWALSyncSource` function in [`packages/collaboration/src/collab/wal.ts`](https://github.com/macro-inc/macro/blob/main/packages/collaboration/src/collab/wal.ts) synchronizes the local update log with the server. The CRDT automatically reconciles any conflicts that occurred during the offline period.

### How are undo and redo operations handled in a collaborative environment?

The system utilizes `loro-crdt`'s `UndoManager`, as demonstrated in [`apps/web/src/lib/core/component/LexicalMarkdown/collaboration/undo.ts`](https://github.com/macro-inc/macro/blob/main/apps/web/src/lib/core/component/LexicalMarkdown/collaboration/undo.ts). This manager tracks local operations separately from remote ones, allowing users to undo their own changes while preserving edits made by collaborators. The undo stack operates on the CRDT's internal operation history, ensuring consistency across the distributed system.