SpecsModelExplore
Overview
IOModel Stack
Reverse ProxyIOModel StudioYjs Realtime ServerKeycloakPostgreSQLRedis
Why it's needed
Deployment considerations
SpecsModelExplore
Yjs Realtime Server
OverviewYjs Realtime Server GuideLinks and Communications

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.

Why it’s needed

  • Conflict-free editing — CRDTs let many people edit the same model/spec simultaneously without locks or merge conflicts.
  • Low latency — changes fan out over a persistent WebSocket instead of request/response polling.
  • Durability — document state is written back to PostgreSQL so a restart doesn’t drop work.

Deployment considerations

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: 3400

Set 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