all work

Relay

(Real-time Chat)

A community chat app with channels, threads and presence that stays snappy with thousands online.

  • <80ms message latency
  • 50k messages / min
  • 4.8★ app rating

2024 · React · Node.js · WebSockets · Redis · Docker

relaychat.app

Problem

(what hurt)

The community lived in a rented chat tool that capped history and exports. They wanted their own space, but a single server fell over at around 800 concurrent users.

Project goal: A remote-first community wanted a chat app it owned, with channels, threads and presence, that feels instant even with thousands of people online.

Architecture

(how it fits together)

Stateless WebSocket gateways sit behind a load balancer. Each message is validated, written to Postgres and published to Redis, which fans it out to every gateway holding sockets for that room.

Tech decisions: A Node WebSocket gateway scaled horizontally with Redis Pub/Sub, optimistic UI in React, messages persisted in Postgres, and everything shipped as Docker containers.

  • React
  • Node.js
  • WebSockets
  • Redis
  • Docker
(architecture)Web clientWS gatewayPostgresRedis
realtime/server.ts
wss.on("connection", (socket, req) => {
  const user = authenticate(req);

  socket.on("message", async (raw) => {
    const msg = MessageSchema.parse(JSON.parse(raw.toString()));
    await db.message.create({ data: { ...msg, authorId: user.id } });
    // fan out to every gateway node in the cluster
    await pub.publish("room:" + msg.roomId, JSON.stringify(msg));
  });
});

sub.on("message", (channel, payload) => {
  rooms.get(channel)?.forEach((s) => s.send(payload));
});

Features

(what it does)

  • Optimistic sending

    Messages appear instantly and reconcile with the server ID when the write lands, so chat never feels laggy.

  • Presence and typing

    Ephemeral presence lives only in Redis with short TTLs, keeping the database free of noise.

  • Threads

    Replies branch off any message without cluttering the channel.

(in use)
ship it ✓
relaychat.app/settings

Challenges

(what was hard)

  1. 01Reconnect storms

    Deploys used to drop every socket at once. Jittered backoff and graceful connection draining fixed it.

  2. 02Ordering

    Server-assigned sequence numbers per room keep messages in order across nodes.

Results

  • <80ms message latency
  • 50k messages / min
  • 4.8★ app rating

Relay now handles 50k messages a minute at peak with sub-80ms delivery, and the community fully moved over in a month.

design & code by Shreya Pathak