The Yjs Realtime Server powers live, multi-user collaboration. It keeps a shared CRDT document per editing session in memory, broadcasts changes over WebSocket, and persists the merged state so nothing is lost on reconnect.
Role in the stack
Clients connect over WebSocket (through the reverse proxy), edits are merged via Yjs CRDTs, and documents are persisted in PostgreSQL. Studio mints the short-lived WS tokens that authorize each connection.
This service is mostly stateless (durable state lives in PostgreSQL) but it is connection-sticky: all clients editing the same document should land on the same instance.
A Deployment with a WebSocket-aware Service. Use session affinity or a
consistent-hash routing strategy so a document’s collaborators share an instance:
apiVersion: v1kind: Servicemetadata: name: yjs-server namespace: iomodelspec: selector: { app: yjs-server } sessionAffinity: ClientIP ports: - port: 3400 targetPort: 3400Set generous Ingress proxy timeouts for the /collab route and prefer a
routing strategy that keeps a room on one pod. Scaling out without affinity
can split a document’s editors across instances.
Shared secret with Studio
COLLAB_JWT_SECRET must match the value Studio uses to sign WS tokens,
otherwise every realtime connection is rejected.
apiVersion: v1
kind: Service
metadata:
name: yjs-server
namespace: iomodel
spec:
selector: { app: yjs-server }
sessionAffinity: ClientIP
ports:
- port: 3400
targetPort: 3400