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

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:

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

As seen in 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. 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 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.

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. 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, this appears as:
const doc = new LoroDoc();
const manager = new LoroManager(doc);
  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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:

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:

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

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 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. 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →