Handling Websockets with Express

Mar 9, 2020

The ws npm module is the de facto library for websockets in Node.js. It has built-in support for Node.js' native http servers. But, unfortunately, very few developers use Node's built-in HTTP package directly, they usually use Express.

Integrating the ws package with Express is easy. There is also an express-ws module on npm, but I've never managed to get that module to work. Here's how you can use the ws package to listen to websockets on an Express server.

Listening to Websockets with Express

The ws package supports native Node.js HTTP servers. Conveniently, Express' listen() function returns a native Node.js HTTP server. So you can use the same process described in the ws docs:

const express = require('express');
const ws = require('ws');

const app = express();

// Set up a headless websocket server that prints any
// events that come in.
const wsServer = new ws.Server({ noServer: true });
wsServer.on('connection', socket => {
  socket.on('message', message => console.log(message));

// `server` is a vanilla Node.js HTTP server, so use
// the same ws upgrade process described here:
// https://www.npmjs.com/package/ws#multiple-servers-sharing-a-single-https-server
const server = app.listen(3000);
server.on('upgrade', (request, socket, head) => {
  wsServer.handleUpgrade(request, socket, head, socket => {
    wsServer.emit('connection', socket, request);


How do you actually connect to this server? ws also has a websocket client implementation as well as the server implementation.

const ws = require('ws');

const client = new ws('ws://localhost:3000');

client.on('open', () => {
  // Causes the server to print "Hello"

Want to become your team's Express expert? There's no better way to really grok a framework than to write your own clone from scratch. In 15 concise pages, this tutorial walks you through how to write a simplified clone of Express called Espresso. Get your copy!

Espresso supports:
  • Route handlers, like `app.get()` and `app.post()`
  • Express-compatible middleware, like `app.use(require('cors')())`
  • Express 4.0 style subrouters
As a bonus, Espresso also supports async functions, unlike Express.

Get the tutorial and master Express today!

Did you find this tutorial useful? Say thanks by starring our repo on GitHub!

More Express Tutorials