Common Mistakes Developers Make When Using Socket.io with WebSockets

Shayan DanishShayan Danish
2 min read

When working with HTTP, developers typically use Express.js to manage routing and server logic at a high level. However, when integrating WebSockets, which follow a different data communication protocol, Socket.io is often the go-to choice.

The Common Mistake

A frequent mistake developers make is using app.listen(port, callback) instead of server.listen(port, callback) when setting up Socket.io with an Express server. Let’s examine why this matters.

Understanding the Correct Approach

Here’s a common setup for an Express app:

const express = require("express");
const app = express();
const http = require("http");
const server = http.createServer(app);
const path = require("path");

const { Server } = require("socket.io");
const io = new Server(server);

At a glance, everything looks fine, but the issue arises when developers mistakenly use:

app.listen(3000, () => {
    console.log("Server is running on port 3000");
});

instead of:

server.listen(3000, () => {
    console.log("Server is running on port 3000");
});

Why server.listen() is Required

  1. WebSocket Upgrades Need a Low-Level Server Instance

    • Express.js (app.listen()) internally creates an HTTP server, but it abstracts away direct control.

    • WebSockets require direct access to the underlying HTTP server to handle connection upgrades.

    • Using server.listen() ensures that Socket.io can properly upgrade the HTTP connection to a WebSocket.

  2. Socket.io Relies on HTTP Server for Connections

    • When creating a new Server(io), we pass the HTTP server (server), not the Express app.

    • If app.listen() is used, WebSocket connections might not function as expected because Express does not expose the underlying server needed for upgrades.

The Right Way to Set Up Socket.io

const express = require("express");
const app = express();
const http = require("http");
const server = http.createServer(app);
const { Server } = require("socket.io");

const io = new Server(server);

io.on("connection", (socket) => {
    console.log("A user connected");

    socket.on("disconnect", () => {
        console.log("A user disconnected");
    });
});

server.listen(3000, () => {
    console.log("Server is running on port 3000");
});

Takeaway

Many developers mistakenly use app.listen() out of habit, but when working with WebSockets and Socket.io, always use server.listen(). This ensures proper WebSocket upgrades and avoids unexpected issues with real-time communication.

By understanding this subtle but crucial difference, you can avoid unnecessary debugging and ensure your WebSocket server functions correctly.

0
Subscribe to my newsletter

Read articles from Shayan Danish directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Shayan Danish
Shayan Danish

Full Stack Developer | Building Products & Crafting Solutions for Everyday Challenges