Build a Startup Cheatsheet

Realtime (WebSockets, WebRTC)

Use this Build a Startup reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

What "Realtime" Actually Means

A traditional web request is: browser asks, server answers, connection closes. Realtime means the server can push data to the browser without the browser asking first — or two browsers can exchange data with very low latency.

The right realtime technology depends on what you are building:

Use caseTechnology
Live notifications, activity feedsServer-Sent Events or WebSockets
Collaborative editing (like Google Docs)WebSockets + OT or CRDT
Live dashboards, data streamingServer-Sent Events or WebSockets
ChatWebSockets
Video/audio callsWebRTC
Multiplayer gamesWebSockets or WebRTC (data channels)
Database change subscriptionsSupabase Realtime, Convex

WebSockets

WebSockets provide a full-duplex, persistent connection between a client and server. Either side can send messages at any time.

How it works: 1. Browser initiates an HTTP handshake requesting protocol upgrade 2. Server agrees; connection upgrades to WebSocket (persistent TCP connection) 3. Messages flow in both directions without re-establishing the connection

Use WebSockets when: - You need bidirectional communication (client sends AND server sends) - You need very low latency (chat, multiplayer, collaborative tools) - You need server-to-client push on arbitrary events

Limitations: - Require a persistent server process — serverless functions (Vercel, Cloudflare Workers) do NOT support WebSockets - Each open connection consumes memory on the server - You must handle reconnection logic on the client (sockets drop; networks are unreliable)

Basic WebSocket Server (Node.js)

const { WebSocketServer } = require("ws");
const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", (ws) => {
  console.log("Client connected");

  ws.on("message", (data) => {
    const message = JSON.parse(data.toString());
    // Broadcast to all connected clients
    wss.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(JSON.stringify({ from: "server", ...message }));
      }
    });
  });

  ws.on("close", () => console.log("Client disconnected"));
});

WebSocket Client (Browser)

const ws = new WebSocket("wss://yourapp.com/ws");

ws.onopen = () => {
  ws.send(JSON.stringify({ type: "join", room: "general" }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  setMessages((prev) => [...prev, data]);
};

ws.onclose = () => {
  // Reconnect logic — exponential backoff
  setTimeout(() => reconnect(), 1000);
};

Socket.IO

Socket.IO is a library built on top of WebSockets that adds:

  • Automatic reconnection with exponential backoff
  • Rooms (broadcast to a subset of clients)
  • Fallback to HTTP long-polling if WebSockets are unavailable
  • Event-based API (cleaner than raw message events)
// Server
const io = new Server(httpServer);
io.on("connection", (socket) => {
  socket.join("room-42");
  socket.to("room-42").emit("user-joined", { id: socket.id });
  
  socket.on("send-message", (data) => {
    io.to("room-42").emit("new-message", data);
  });
});

// Client
const socket = io("https://yourapp.com");
socket.emit("send-message", { text: "Hello!" });
socket.on("new-message", (data) => console.log(data));

When to use Socket.IO: You want the convenience layer; you need rooms and reconnection out of the box; you are building chat or collaborative features quickly. The overhead is minimal for most use cases.

Server-Sent Events (SSE)

SSE is a one-way channel: the server pushes data to the browser over a persistent HTTP connection. The browser cannot send data back through the same connection.

When to use SSE: - Live notifications, activity feeds, progress updates, streaming AI responses - You only need server-to-client push (no bidirectional communication) - You want to stay on serverless platforms like Vercel — SSE works in Next.js API routes

SSE is simpler than WebSockets for read-only streaming use cases.

// Next.js API route — streaming SSE
export async function GET() {
  const encoder = new TextEncoder();

  const stream = new ReadableStream({
    start(controller) {
      const send = (data: object) => {
        controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}\n\n`));
      };

      // Send a message every second for 10 seconds
      let count = 0;
      const interval = setInterval(() => {
        send({ type: "update", count });
        if (++count >= 10) {
          clearInterval(interval);
          controller.close();
        }
      }, 1000);
    },
  });

  return new Response(stream, {
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      Connection: "keep-alive",
    },
  });
}

// Client
const source = new EventSource("/api/events");
source.onmessage = (e) => {
  const data = JSON.parse(e.data);
  setUpdates((prev) => [...prev, data]);
};

SSE is the mechanism behind streaming AI chat responses (ChatGPT-style typing effect).

WebRTC

WebRTC (Web Real-Time Communication) enables peer-to-peer communication between two browsers. Unlike WebSockets (which go through your server), WebRTC data flows directly browser-to-browser after the initial handshake.

What WebRTC enables: - Video calls (camera/microphone streams) - Voice calls - Peer-to-peer file transfer - Low-latency data channels (multiplayer games)

How it works (simplified): 1. Both browsers connect to a signaling server (your server, via WebSockets) to exchange connection metadata (SDP offer/answer) 2. They use STUN/TURN servers to discover their public IP addresses and traverse NATs/firewalls 3. Once connected, media/data flows peer-to-peer (bypassing your server entirely)

STUN servers — help browsers discover their public IP. Google provides free STUN servers: stun:stun.l.google.com:19302.

TURN servers — relay traffic when peer-to-peer is blocked by a firewall. You must run or pay for TURN. Twilio's TURN network and Metered TURN offer hosted options.

When NOT to Build Video Calls from Scratch

WebRTC is notoriously complex. For most startups, use a managed real-time video platform:

PlatformFree tierBest for
Daily.co2,000 min/monthFastest integration; excellent React SDK
LivekitSelf-hostableOpen-source; production-grade; WebRTC + SFU
Agora10,000 min/monthMobile SDKs; large enterprise ecosystem
Twilio VideoPay-per-useReliable; Twilio ecosystem
100ms10,000 min/monthGood DX; competitive pricing

Managed Realtime Platforms

If you want realtime database sync or collaborative state without managing WebSocket infrastructure yourself:

PlatformTypeBest for
Supabase RealtimePostgres CDC subscriptionsListening to database changes; presence
ConvexReactive queriesFull-stack reactivity; query re-runs on data change
LiveblocksCollaborative stateGoogle Docs-style collaboration; comments, presence
PartyKitWebSocket roomsMultiplayer; simple room-based pub/sub
PusherManaged WebSocket channelsClassic choice; good free tier; easy setup
AblyPub/sub at scaleHigh-reliability; enterprise-grade; global

Supabase Realtime

const channel = supabase
  .channel("posts-changes")
  .on("postgres_changes", { event: "INSERT", schema: "public", table: "posts" }, (payload) => {
    setFeed((prev) => [payload.new, ...prev]);
  })
  .subscribe();

// Cleanup
return () => supabase.removeChannel(channel);

Pusher

// Server: trigger an event
const pusher = new Pusher({ appId, key, secret, cluster });
await pusher.trigger("chat-room", "new-message", { text, userId });

// Client: subscribe
const pusher = new PusherJS(key, { cluster });
const channel = pusher.subscribe("chat-room");
channel.bind("new-message", (data) => {
  setMessages((prev) => [...prev, data]);
});

Pusher free tier: 200 concurrent connections, 200,000 messages/day.

Choosing the Right Approach

NeedRecommended approach
Streaming AI responsesSSE in Next.js API route
Live notifications / feed updatesSSE or Supabase Realtime
Chat applicationSocket.IO on Railway, or Pusher
Collaborative editingLiveblocks (managed) or Yjs + WebSockets
Multiplayer gameWebSockets + Socket.IO rooms
Video callsDaily.co or Livekit (managed)
Database-driven realtimeSupabase Realtime or Convex
Real-time dashboardSSE or WebSockets from a persistent server

Deployment Considerations

WebSockets require a persistent server process. This means:

  • Vercel functions will NOT work for WebSocket servers (15-second timeout; stateless)
  • You need Railway, Render, Fly.io, or a VM to host a WebSocket server
  • Alternatively, use a managed service (Pusher, Ably, Liveblocks) that handles the WebSocket infrastructure

SSE works on Vercel — each SSE connection is just a long HTTP response, which Vercel supports.