Creating Node.js WebSocket Server
1. Installing ws Library
| Package | Notes |
|---|---|
ws | De-facto standard, no deps |
uWebSockets.js | C++ binding, highest perf |
socket.io | WS + fallbacks + rooms |
2. Creating WebSocket Server
Example: Minimal server
import { WebSocketServer } from "ws";
const wss = new WebSocketServer({ port: 8080 });
wss.on("connection", (ws, req) => {
ws.on("message", (data, isBinary) => ws.send(data, { binary: isBinary }));
});
| Option | Description |
|---|---|
port | Bind port |
host | Bind interface |
server | Attach to existing http server |
path | Only accept this URL path |
noServer | Manual upgrade handling |
3. Handling Server Events
| Event | Args |
|---|---|
connection | (ws, req) |
error | (err) |
close | () |
headers | (headers, req) |
listening | () |
4. Accessing Client Connections
Example: Iterate clients
for (const client of wss.clients) {
if (client.readyState === 1) client.send(payload);
}
| Property | Detail |
|---|---|
wss.clients | Set<WebSocket> |
clientTracking: false | Disable set (save memory) |
5. Handling Client Events
| Event | Args |
|---|---|
message | (data, isBinary) |
close | (code, reason) |
error | (err) |
ping / pong | (data) |
open | () — client only |
6. Accessing Request Info
Example: Read headers
wss.on("connection", (ws, req) => {
const ip = req.headers["x-forwarded-for"] ?? req.socket.remoteAddress;
const ua = req.headers["user-agent"];
const url = new URL(req.url, `http://${req.headers.host}`);
});
| Field | From |
|---|---|
req.url | Path + query |
req.headers | HTTP upgrade headers |
req.socket.remoteAddress | Peer IP |
7. Implementing HTTP Server Integration
Example: Share port with Express
import http from "node:http";
import express from "express";
import { WebSocketServer } from "ws";
const app = express();
const server = http.createServer(app);
const wss = new WebSocketServer({ server, path: "/ws" });
server.listen(3000);
| Approach | Use |
|---|---|
{ server } | Single port for HTTP + WS |
{ noServer: true } | Manual upgrade handling for routing |
8. Handling Multiple Servers
Example: Path-based routing
const chat = new WebSocketServer({ noServer: true });
const feed = new WebSocketServer({ noServer: true });
server.on("upgrade", (req, sock, head) => {
const { pathname } = new URL(req.url, "http://x");
const target = pathname === "/chat" ? chat : pathname === "/feed" ? feed : null;
if (!target) return sock.destroy();
target.handleUpgrade(req, sock, head, (ws) => target.emit("connection", ws, req));
});
9. Gracefully Shutting Down Server
| Step | Action |
|---|---|
| 1 | Stop accepting new connections (wss.close()) |
| 2 | Broadcast going-away (1001) |
| 3 | Wait for client close or timeout |
| 4 | Terminate remaining sockets |
| 5 | Close HTTP server |
10. Broadcasting Messages
Example: Broadcast helper
function broadcast(msg, filter = () => true) {
const data = typeof msg === "string" ? msg : JSON.stringify(msg);
for (const c of wss.clients) {
if (c.readyState === 1 && filter(c)) c.send(data);
}
}
| Pattern | Use |
|---|---|
| All clients | Server-wide announcement |
| Room/topic | Tag clients with channel set |
| Exclude sender | Chat fan-out |