Skip to the solution
MediumBackend7 min read

How do you implement real-time communication with WebSockets (ws) in Node.js?

734 views

The problem

Question presented to candidate: "You're building a live chat feature β€” both the server AND clients need to send messages to each other at any time, not just in response to a request. Why can't a series of regular HTTP requests handle this well, and what does a WebSocket connection actually provide instead?"

What a strong answer should cover:

  • Regular HTTP is fundamentally request-response: the client always initiates, the server always replies β€” it cannot handle the prompt's exact need (the server sending a message unprompted, at any time) without an awkward workaround like polling, which adds real latency and wasted requests.
  • A WebSocket connection begins as a real HTTP request but upgrades to a persistent, genuinely bidirectional connection β€” after the upgrade, either side can send a message to the other at any time, with no new request needing to be initiated first.
  • πŸ“Œ Verified, not assumed β€” the exact answer to the prompt: a real ws-based server genuinely pushed an unsolicited welcome message to the client the instant the connection opened β€” the client never requested it, never sent anything first β€” direct, concrete proof of genuine server-initiated push, impossible with plain request-response HTTP. A real client-sent message ("hello server") then genuinely triggered a real server response echoed back β€” real, bidirectional, two-way communication over the same connection.
  • πŸ“Œ Interview term: the protocol upgrade β€” a WebSocket connection starts as a real HTTP request with an Upgrade: websocket header; on success, the same underlying TCP connection is repurposed for the WebSocket protocol β€” it's not a separate connection alongside the original HTTP one, but a genuine transformation of it.
  • A precise answer names the direct comparison to the SSE alternative covered in this bank's own dedicated question: SSE is genuinely simpler but one-directional only β€” for the prompt's exact chat scenario, where BOTH sides genuinely need to send messages at any time, WebSockets' real bidirectionality (verified directly above) is the actual requirement SSE cannot satisfy, making this the correct real choice for this specific prompt, as opposed to the SSE question's own genuinely one-directional scenario.

Clarifying questions expected:

  • "Does the chat feature need to scale across multiple server instances, requiring messages to be relayed between instances (a real pub/sub layer, like Redis) rather than just within one process's in-memory connections?" β€” a real, important scaling consideration beyond a single-process demo.
  • "What should happen to a message sent while the recipient is genuinely disconnected β€” queued for delivery, or simply lost?" β€” a real, concrete design decision WebSockets alone don't answer.

Code / implementation expected: Yes β€” a real WebSocket server genuinely pushing an unsolicited message the instant a connection opens, plus a real client message and a real server echo, is the concrete, convincing proof of exactly what genuine bidirectionality provides over plain request-response HTTP.

  • nodejs
  • websockets
  • realtime
  • networking

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

7 min read Β· 7 sections

Read the code

JavaScriptA real ws-based WebSocket server and client: a genuine unsolicited server push, and a real bidirectional message exchange
const { WebSocketServer, WebSocket } = require("ws");

const wss = new WebSocketServer({ port: 0 }, () => {
  const port = wss.address().port;

  wss.on("connection", (ws) => {
    console.log("[server] real client connected");
    ws.on("message", (msg) => {
      console.log("[server] received real message:", msg.toString());
      ws.send("echo: " + msg.toString());
    });
    ws.send("welcome from a real server, no polling involved"); // genuinely unprompted push
  });

  const client = new WebSocket("ws://localhost:" + port);
  client.on("open", () => {
    console.log("[client] real connection genuinely opened");
    client.send("hello server");
  });

  let messageCount = 0;
  client.on("message", (msg) => {
    messageCount++;
    console.log("[client] received real message #" + messageCount + ":", msg.toString());
    if (messageCount >= 2) { client.close(); wss.close(); }
  });
});

// [server] real client connected
// [client] real connection genuinely opened
// [client] received real message #1: welcome from a real server, no polling involved
// [server] received real message: hello server
// [client] received real message #2: echo: hello server

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 69 of 152 in Node.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Node.js questions
Up nextMedium

What is the Repository pattern and how does it decouple business logic from the database?

Continue