go-yjs-relay is a pure-Go (no cgo) implementation of the server side of the
Yjs y-websocket protocol as a
relay hub. It multiplexes collaborative-editing connections into rooms and fans
each client's binary frames out to the rest of the room โ the exact relay-only deployment mode the
upstream y-websocket server uses. It is transport-agnostic: it imports no
WebSocket library, so the caller drives a Membership handle from any Go WebSocket
stack. It is a relay, not a server-side CRDT โ it does not decode Yjs updates;
clients reconcile among themselves via Yjs's update + sync-step algebra, which keeps the server
forward-compatible with new y-protocols versions for free and a few hundred lines instead of a
several-thousand-line Go Yjs implementation. Pure stdlib (context + sync),
100% coverage under -race, CI green across 6 arches.
Rooms & Hub multiplexing ready
One Room per collaborative document, keyed by room ID. Hub.Join inserts a connection and hands back a Membership handle; Hub.MembersCount surfaces the live peer count that is the bidirectional-sync precondition.
Fan-out broadcast ready
Every binary frame a member Sends is delivered to every other member’s Recv channel โ echo-suppressed, so a client never sees its own frame. The fan-out runs under a tight per-room lock, microseconds even at hundreds of members.
Slow-peer drop & room GC ready
A member whose receive buffer is full has the frame dropped rather than blocking the hub โ Yjs re-syncs it via the next sync-step handshake. One straggler never stalls the room, and the room is reclaimed when its last member leaves.
Lifecycle: idempotent & context-driven leave ready
Membership.Leave is idempotent (safe from a deferred cleanup and a watcher at once); LeaveOnContextDone(ctx) unregisters the connection when its request context cancels, saving the caller a goroutine.
Transport-agnostic core & coverage ready
No WebSocket library is imported: the Membership handle is the seam any transport plugs into (nhooyr, gorilla, net/http, or an in-memory pipe). 100% coverage under -race, gofmt + go vet clean, green across all six 64-bit Go arches.
Persistence & snapshotting planned
Downstream by design: the relay holds no durable state. Persistence is bolted on by serialising the last update from any one client to a backing store โ an opt-in layer above the relay, not part of the hub.
- ready capability complete (exit criteria met, nothing material left)
- active in progress (substantial work shipped, not yet finished)
- planned not started yet (or downstream by design)
A compact, robust relay: room multiplexing, echo-suppressed fan-out, non-blocking
slow-peer drop, automatic room GC on the last leave, idempotent and context-driven
Leave. No WebSocket library is baked in โ the Membership handle is the seam
any transport plugs into (nhooyr.io/websocket, gorilla/websocket,
net/http, or an in-memory pipe in tests). CGO-free, so it cross-compiles and embeds
anywhere. Part of the github.com/go-yjs-relay org.