Building Real-time Collaborative Applications
12/15/2023
18 min read
Tridip Dutta
Backend

Building Real-time Collaborative Applications

Learn to build Google Docs-style collaborative features using operational transforms, CRDTs, and real-time synchronization techniques.

Real-time
Collaboration
WebSockets
CRDT

Building Real-time Collaborative Applications

From shared documents and whiteboards to multiplayer coding and real-time design tools—collaborative applications are changing the way we work and communicate. At the heart of these systems lies real-time synchronization, conflict resolution, and state consistency across users.

In this post, we'll explore how to build collaborative experiences using WebSockets, CRDTs (Conflict-free Replicated Data Types), and Operational Transforms (OT). You'll get insights into the architecture, core techniques, and performance considerations that power tools like Google Docs, Notion, and Figma.


Why Build Collaborative Applications?

Real-time collaboration boosts productivity and enables entirely new workflows. Consider:

  • Teams co-editing a document
  • Designers collaborating on a shared canvas
  • Developers pair-programming across the globe
  • Educators and students solving problems together

This demands:

  • Instant visibility of others' changes
  • Conflict-free merging of edits
  • Low-latency data syncing

Core Components of a Collaborative System

To implement a real-time collaborative system, you’ll typically need:

  • WebSocket or WebRTC layer for live communication
  • State synchronization logic (CRDTs or OT)
  • Persistence layer for saving user data
  • Awareness protocols (for showing cursors, selections, etc.)

Setting Up WebSockets for Real-time Communication

Backend (Node.js with ws)

npm install ws
// server.js
import { WebSocketServer } from 'ws'

const wss = new WebSocketServer({ port: 8080 })

const clients = new Set()

wss.on('connection', (ws) => {
  clients.add(ws)
  console.log('User connected')

  ws.on('message', (message) => {
    // Broadcast to all other clients
    for (let client of clients) {
      if (client !== ws && client.readyState === ws.OPEN) {
        client.send(message)
      }
    }
  })

  ws.on('close', () => {
    clients.delete(ws)
  })
})

Frontend Client

<script>
  const socket = new WebSocket('ws://localhost:8080')

  socket.onmessage = (event) => {
    const update = JSON.parse(event.data)
    // Apply update to the local editor
  }

  function sendUpdate(update) {
    socket.send(JSON.stringify(update))
  }
</script>

Operational Transforms (OT) vs. CRDTs

Two leading techniques for conflict resolution:

FeatureOTCRDT
OriginGoogle DocsAutomerge, Yjs
Conflict handlingServer-controlledPeer-to-peer
ComplexityHigher (ordering, intent)Lower (state convergence)
Offline supportLimitedNative
Ideal forCentralized systemsDecentralized apps

Building with CRDTs (e.g., Yjs)

Yjs is a powerful CRDT framework for building collaborative editors.

Install Yjs and WebSocket Provider

npm install yjs y-websocket

Backend

import * as http from 'http'
import WebSocket from 'ws'
import { setupWSConnection } from 'y-websocket/bin/utils.js'

const server = http.createServer()
const wss = new WebSocket.Server({ server })

wss.on('connection', (conn, req) => {
  setupWSConnection(conn, req)
})

server.listen(1234)

Frontend

<script type="module">
  import * as Y from 'yjs'
  import { WebsocketProvider } from 'y-websocket'

  const doc = new Y.Doc()
  const provider = new WebsocketProvider('ws://localhost:1234', 'my-doc', doc)

  const yText = doc.getText('shared-text')

  yText.observe((event) => {
    console.log('Document changed:', yText.toString())
  })

  // Link this with a text editor (e.g., CodeMirror, ProseMirror)
</script>

Awareness: Presence, Cursors & More

To replicate a Google Docs–like experience, show:

  • Active users
  • Real-time cursors/selections
  • Editing state (typing, idle, etc.)

Yjs supports this with awarenessProtocol.

const awareness = provider.awareness
awareness.setLocalStateField('user', {
  name: 'Tridip',
  color: '#00aaff',
})

Handling Persistence

While Yjs holds in-memory state, you can persist data using:

  • IndexedDB (for offline-first apps)
  • A database (e.g., MongoDB, PostgreSQL)
  • Yjs + LevelDB or y-indexeddb

Example: Save document snapshots periodically or on disconnect.


Security & Access Control

Real-time systems must be secured just like REST APIs:

  • Authenticate users using JWT/session
  • Authorize access to shared documents
  • Validate updates before applying
  • Encrypt traffic (use wss:// in production)
// Example using token
io.use((socket, next) => {
  const token = socket.handshake.auth?.token
  if (validateToken(token)) {
    next()
  } else {
    next(new Error('Unauthorized'))
  }
})

Performance Optimization

  • Throttle update frequency (e.g., debounce keystrokes)
  • Chunk large updates (e.g., paste events)
  • Use binary encoding in CRDTs to reduce payloads
  • Avoid memory leaks by cleaning up listeners and inactive clients

Real-World Use Cases

  1. Document Editors – Google Docs, Notion, Dropbox Paper
  2. Design Tools – Figma, Miro, Excalidraw
  3. Education Platforms – Real-time whiteboards, quizzes
  4. Dev Tools – Pair programming, live coding

Scaling Considerations

  • Use Redis Pub/Sub to sync WebSocket messages across nodes
  • Store documents in S3, PostgreSQL, or Firestore
  • Consider Yjs + y-websocket + Redis Adapter for horizontal scaling

Conclusion

Collaborative applications are no longer futuristic—they’re essential. With the right mix of WebSockets, CRDTs, and UI synchronization, you can create seamless, multiplayer-like experiences across devices and teams.

Whether you're building a live coding platform, an educational whiteboard, or the next big productivity tool, the techniques here will help you architect a scalable, real-time backend.


Resources


Want more posts like this? Follow the blog for deep dives into collaborative data structures, CRDT scaling, and secure WebSocket deployments.

TD

About Tridip Dutta

Creative Developer passionate about creating innovative digital experiences and exploring AI. I love sharing knowledge to help developers build better apps.