We understood why Socket.IO needs a persistent server. Now let's actually build it. By the end of this post, your project will run through a custom server instead of the default next dev process.
Step 1: Install the Required Packages
We will use tsx to run our TypeScript server directly, without a separate compile step. From your project root, run:
npm install socket.io npm install --save-dev tsx @types/node cross-env
We are only installing socket.io for now (the server-side package). We will install socket.io-client in the next post, when we build the client side.
Step 2: Create the Custom Server File
Create a new file called server.ts at the root of your project, at the same level as package.json (outside the src folder).
import { createServer } from "http"; import { parse } from "url"; import next from "next"; import { Server } from "socket.io";
const dev = process.env.NODE_ENV !== "production"; const hostname = "localhost"; const port = parseInt(process.env.PORT || "3000", 10);
const app = next({ dev, hostname, port }); const handle = app.getRequestHandler();
app.prepare().then(() => { const httpServer = createServer((req, res) => { const parsedUrl = parse(req.url!, true); handle(req, res, parsedUrl); });
const io = new Server(httpServer, { path: "/api/socket", });
io.on("connection", (socket) => { console.log("A client connected:", socket.id);
socket.on("disconnect", () => { console.log("Client disconnected:", socket.id); }); });
httpServer.listen(port, () => { console.log(`Server ready on http://${hostname}:${port}`); }); });
Let's break down what each part is doing:
next({ dev, hostname, port })creates the Next.js app instance, the same one that normally runs behindnext devhandleis the function that lets Next.js process every normal page and route requestcreateServer(...)creates one plain Node.js HTTP server, and every incoming request is handed off to Next.js throughhandlenew Server(httpServer, ...)attaches Socket.IO to that exact same HTTP server, instead of creating a separate one- The
path: "/api/socket"option tells Socket.IO which URL path to listen on for its own connections, so it does not clash with your normal Next.js routes io.on("connection", ...)runs every time a new client connects, and we currently just log it
Step 3: Update Your package.json Scripts
Open package.json and replace the existing scripts section with this:
"scripts": { "dev": "tsx watch server.ts", "build": "next build", "start": "cross-env NODE_ENV=production tsx server.ts", "lint": "eslint" }
Here is what changed:
devnow runsserver.tsusingtsx watch, which restarts the server automatically whenever you save a file, similar to hownext devbehaved beforestartruns the same server file, but withNODE_ENV=production, so Next.js knows to serve the optimized production build instead of development modebuildstays exactly the same, since building the Next.js app is unrelated to which server runs it afterward
Step 4: Run the Custom Server
Stop any previous next dev process that might still be running, then start the project again with:
npm run dev
You should see this in your terminal:
Server ready on http://localhost:3000
Open http://localhost:3000 in your browser. Your Next.js app should load exactly as before. Nothing looks different on the surface, but under the hood, your app is now running through the custom server we just built, with Socket.IO already attached and listening.
Step 5: Confirm Socket.IO Is Actually Running
Right now, nothing in our frontend tries to connect yet, so you will not see any connection logs. That is expected, since we have not written any client-side code. We are simply confirming the server starts correctly and is ready to accept connections once we do.
A Note on next build
One important detail: running next build will still work fine, since it only builds the Next.js application itself. But you must always start the app afterward using npm run start, which runs through server.ts. Running the plain next start command directly will not include Socket.IO at all, since that command boots the default Next.js server, not our custom one.
Summary
- We installed
socket.ioandtsx, then created aserver.tsfile at the project root - This file creates one plain HTTP server, hands normal requests to Next.js, and attaches Socket.IO to the same server on a dedicated path
- We updated
package.jsonso bothdevandstartrun through this custom server instead of the default Next.js server - The app currently starts correctly with Socket.IO attached, but nothing connects to it yet, since we have not written any client-side code
In the next post, we will install socket.io-client, add proper TypeScript types, and connect our React frontend to this server for the first time.
No comments:
Post a Comment