Realtime SDK

Document Sync

Document Sync

Realtime SDK uses Yjs for conflict-free collaborative editing. Multiple users can edit the same document simultaneously without conflicts.

How It Works

Yjs uses CRDTs (Conflict-free Replicated Data Types) to automatically merge changes from multiple users. There's no need for operational transforms or manual conflict resolution.

Basic Setup

import { useDocument } from '@realtime-sdk/react';
import * as Y from 'yjs';
 
function CollaborativeEditor({ room }) {
  const { doc, synced } = useDocument(room, 'main');
 
  if (!synced) {
    return <div>Loading document...</div>;
  }
 
  return <Editor yDoc={doc} />;
}

Yjs Data Types

Yjs provides several shared data types:

Y.Text

For rich text editing:

const yText = doc.getText('content');
 
// Insert text
yText.insert(0, 'Hello, ');
yText.insert(7, 'world!');
 
// Get content
console.log(yText.toString()); // "Hello, world!"

Y.Array

For ordered lists:

const yArray = doc.getArray('items');
 
// Add items
yArray.push(['Item 1', 'Item 2']);
 
// Get items
console.log(yArray.toArray()); // ['Item 1', 'Item 2']

Y.Map

For key-value data:

const yMap = doc.getMap('settings');
 
// Set values
yMap.set('theme', 'dark');
yMap.set('fontSize', 14);
 
// Get values
console.log(yMap.get('theme')); // 'dark'

Editor Integrations

TipTap

import { useEditor } from '@tiptap/react';
import Collaboration from '@tiptap/extension-collaboration';
import CollaborationCursor from '@tiptap/extension-collaboration-cursor';
 
function TipTapEditor({ room }) {
  const { doc, provider } = useDocument(room, 'main');
  const { self } = usePresence(room);
 
  const editor = useEditor({
    extensions: [
      StarterKit.configure({ history: false }),
      Collaboration.configure({ document: doc }),
      CollaborationCursor.configure({
        provider,
        user: { name: self?.data.name, color: self?.color },
      }),
    ],
  });
 
  return <EditorContent editor={editor} />;
}

CodeMirror

import { yCollab } from 'y-codemirror.next';
 
function CodeMirrorEditor({ room }) {
  const { doc, awareness } = useDocument(room, 'main');
  const yText = doc.getText('code');
 
  const extensions = [
    yCollab(yText, awareness),
    // ... other extensions
  ];
 
  return <CodeMirror extensions={extensions} />;
}

Persistence

Documents are automatically persisted to the server:

  1. Changes are saved with a 2-second debounce
  2. On page load, the server sends the saved state
  3. Reconnecting clients receive any missed updates

Undo/Redo

Yjs supports collaborative undo with per-user stacks:

import { UndoManager } from 'yjs';
 
const yText = doc.getText('content');
const undoManager = new UndoManager(yText);
 
// Undo the last change (only yours)
undoManager.undo();
 
// Redo
undoManager.redo();

Offline Support

Changes made offline are queued and synced when reconnecting:

const { status, pendingChanges } = useDocument(room, 'main');
 
if (status === 'offline') {
  return <div>Offline - {pendingChanges} changes pending</div>;
}

On this page