Workshop recap

BUILD AT SCALE — August 2026

Corgi Cafe · Shoreditch, London

We took a realtime chat app, ran multiple copies of it, deliberately broke live messaging, and used the failure to understand why distributed systems need different architectural choices.

Bright orange exterior of Corgi Cafe in Shoreditch, the BUILD AT SCALE workshop venue

Workshop

Build it. Scale it. Break it.

We started with a small realtime room-based chat application, then changed one assumption at a time.

  1. 01One server
  2. 02Multiple servers
  3. 03Shared database
  4. 04Local WebSocket connections
  5. 05Broken cross-instance realtime delivery
  6. 06Shared event distribution

The point was not to memorise Kubernetes or Kafka. It was to see a system fail, form a hypothesis about why, make an architectural choice and test the same failure again.

BUILD AT SCALE LIVE interface inviting participants to choose a display name and join the workshop network

What we built

The live workshop network.

Attendees worked with a realtime chat product and followed it from a simple single-service system to a multi-instance architecture.

  • React + TypeScript
  • Node.js + TypeScript
  • WebSockets
  • PostgreSQL
  • Docker
  • Kafka
  • Load testing with k6

💬 Join the live workshop chat

We’ll use the shared BUILD AT SCALE chat throughout the session for questions, experiments and results.

→ Enter the live chat

The experiment

We scaled the system and broke the product.

With one chat-service process, realtime messaging worked.

Then we ran two chat-service instances with Kafka disabled. Alice could connect to Chat A while Bob connected to Chat B. Alice’s message was stored in shared PostgreSQL, but Bob might not receive it live. After refreshing, the durable message could appear in history.

Alice
Chat A
PostgreSQL
Shared history
Bob
Chat B

How can a message be stored successfully but still fail to arrive live?

PostgreSQL was shared, but active WebSocket connections belonged to individual application processes.

Durable does not mean delivered live.

The architecture choice

Now we had a reason to introduce Kafka.

Not because it is “the thing scalable apps use”, but because each chat instance owned different local WebSocket connections and every instance needed to see the event.

  1. POST message
  2. PostgreSQL persistence
  3. Kafka · chat.messages
  4. Chat A + Chat B consume
  5. Each broadcasts to its browsers

3 partitionswithin the topic

Keyed by roomIdfor room-level routing

Distinct groupsone per chat instance

What we were actually learning

The trade-offs behind data-intensive systems.

Reliability

What does it mean for a message to be durable versus delivered?

Scalability

What workload are we scaling: users, connections, messages or rooms?

Distribution

What changes when state that lived in one process is split across several?

Ordering

Kafka orders within a partition; roomId gives us useful room-level routing.

Measurement

“Scalable” means little without load parameters and latency and error measurements.

The workshop’s questions are informed by the systems thinking in Martin Kleppmann’s Designing Data-Intensive Applications.

Keep building

Run the experiment yourself.

The workshop guide walks through the system from the simple version to the multi-instance failure and the architecture choices that follow.