I am developing a Next.js application with a custom server to implement WebSockets.
Initially, I used the Socket.IO library, which worked fine in a local environment. However, when I uploaded the application to Render, connection issues arose: WebSocket took a long time to establish a connection, and when it did, it resorted to long polling instead of WebSocket.
I suspected that Render had limitations with WebSockets, but when I checked the available examples, I found a real-time chat written in GoLang that worked fine. This led me to conclude that the problem might be with the SocketIO library. I then tested it with native WebSockets, and the application worked perfectly in production.
However, SocketIO offers several additional features that could be useful, as they are extensively tested and ready to use. I would like to better understand why SocketIO does not work well in this environment, while native WebSockets work without problems.
server.ts with Native Websockets:
import { createServer } from "node:http";
import next from "next";
import { WebSocketServer } from "ws";
const dev = process.env.NODE_ENV !== "production";
const hostname = "localhost";
const port = 10000;
const app = next({ dev, hostname, port });
const handler = app.getRequestHandler();
app.prepare().then(() => {
const httpServer = createServer(handler);
new WebSocketServer({ server: httpServer });
httpServer.once("error", onError).listen(port, () => console.log(`> Ready on http://${hostname}:${port}`));
});
function onError(err: Error) {
console.error(err);
process.exit(1);
}
server.ts with Socket.IO:
import { createServer } from "node:http";
import next from "next";
import { Server } from "socket.io";
const dev = process.env.NODE_ENV !== "production";
const hostname = "localhost";
const port = 10000;
const app = next({ dev, hostname, port });
const handler = app.getRequestHandler();
app.prepare().then(() => {
const httpServer = createServer(handler);
new Server(httpServer, {
transports: ["websocket"],
httpCompression: false,
pingInterval: 25000,
pingTimeout: 5000,
cors: {
origin: process.env.NEXT_PUBLIC_URL,
methods: ["GET", "POST"],
credentials: true,
},
});
httpServer.once("error", onError).listen(port, () => console.log(`> Ready on http://${hostname}:${port}`));
});
function onError(err: Error) {
console.error(err);
process.exit(1);
}
Adding some logs, I can see that the client connection reaches the server, but sending and receiving messages does not work.