Glossary

WebSocket

A WebSocket is a persistent, full-duplex communication channel between a browser and server over a single TCP connection, enabling real-time bidirectional messaging without the overhead of repeated HTTP requests.

Explanation

HTTP is request-response: the client initiates every exchange. For real-time features (chat, live scores, collaborative editing, stock tickers), polling — repeatedly asking the server "any updates?" — is wasteful. WebSockets solve this with a persistent connection: either side can send messages at any time. A WebSocket connection starts as HTTP and upgrades via the Upgrade header. After the handshake, the connection is persistent and the HTTP overhead is gone — messages are framed TCP data. The server can push messages to the client without the client asking. Both sides can send messages simultaneously (full-duplex). Use WebSockets when: you need real-time bidirectional communication (chat, multiplayer games, collaborative tools), the server needs to push data without a client request (live notifications, live score updates), or latency is critical. Use Server-Sent Events (SSE) when you only need server-to-client streaming (news feeds, progress updates) — SSE is simpler and works over regular HTTP. Use polling (setInterval + fetch) for infrequent updates where simplicity outweighs efficiency. WebSockets require persistent server connections — they don't work well with stateless serverless functions (each Lambda invocation is independent). For WebSocket-at-scale, you typically need a connection manager (AWS API Gateway WebSocket, Pusher, Ably, Soketi) or sticky sessions that route a client's requests to the same server instance. Horizontal scaling with WebSockets requires careful architecture.

Code Example

javascript
// WebSocket client and server (Node.js ws library)

// Server (Node.js)
const { WebSocketServer } = require('ws');
const wss = new WebSocketServer({ port: 8080 });

const clients = new Set();

wss.on('connection', (ws) => {
  clients.add(ws);
  console.log('Client connected. Total:', clients.size);

  ws.on('message', (data) => {
    const msg = JSON.parse(data);
    // Broadcast to all other clients
    clients.forEach(client => {
      if (client !== ws && client.readyState === WebSocket.OPEN) {
        client.send(JSON.stringify({ from: msg.user, text: msg.text }));
      }
    });
  });

  ws.on('close', () => clients.delete(ws));
});

// Browser client
const ws = new WebSocket('ws://localhost:8080');

ws.onopen    = () => console.log('Connected');
ws.onmessage = (e) => console.log('Received:', JSON.parse(e.data));
ws.onerror   = (e) => console.error('Error:', e);
ws.onclose   = () => console.log('Disconnected');

// Send a message
ws.send(JSON.stringify({ user: 'Alice', text: 'Hello!' }));

Why It Matters for Engineers

Real-time features are table stakes for modern applications — users expect live notifications, instant chat, live data updates. Knowing when to reach for WebSockets vs simpler alternatives (SSE, polling) is a practical architectural skill. Many vibe-coded real-time features use polling in a loop, creating unnecessary load; WebSockets (or SSE) are the correct tool. WebSocket architecture also exposes important distributed systems trade-offs: stateful persistent connections vs. stateless request/response. Understanding why WebSockets are harder to scale horizontally than HTTP APIs builds the intuition for why stateless architectures are favored in cloud-native design.

Related Terms

HTTP · REST API · Event Loop · Middleware

Learn This In Practice

Go deeper with the full module on Beyond Vibe Code.

Web Development Fundamentals → →