I am working on a full-stack application using Next.js with TypeScript, and I need to use Socket.IO for real-time features. To achieve this, I have created a custom server (src/server.ts) to set up Socket.IO on startup.
Everything works perfectly in development mode when I run the app using:
npm run dev
However, when I try to run the application in production mode, I encounter issues. Here’s how I run it:
- Build the app:
next build
- Start server:
npm run start
The server starts without errors, but when I access any page in the browser, I get the following error:
SyntaxError: Invalid left-hand side in for-in loop: Must have a single binding.
at <unknown> (.next/server/chunks/675.js:3414)
Here is my src/server.ts file:
import next from "next";
import { Server } from "socket.io";
import logger from "./logger";
const dev = process.env.NODE_ENV !== "production";
const hostname = process.env.APP_HOSTNAME;
const port = Number(process.env.APP_PORT) || 3000;
const app = next({ dev, hostname, port });
const handler = app.getRequestHandler();
app
.prepare()
.then(() => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const server = createServer(handler);
const io = new Server(server, {
cors: {
origin: "*",
methods: ["GET", "POST"],
},
});
io.on("connection", (socket) => {
logger.info("A client connected");
socket.on("disconnect", () => {
logger.info("Client disconnected");
});
});
server
.once("error", (err) => {
console.error(err);
process.exit(1);
})
.listen(port, () => {
logger.info(`Server started on http://${hostname}:${port}`);
});
})
.catch((error: unknown) => {
logger.error("Error starting the server: ", error);
process.exit(1);
});
I suspect the issue is related to how Next.js handles the build output in production mode. I’m fairly new to Next.js and TypeScript, so I might be missing something critical. I’ve also tried adding output: "standalone", but the issue still occurs.
package.json
{
"name": "nextjsapp",
"version": "1.0.0",
"description": "Template for web apps",
"main": "dist/index.js",
"scripts": {
"dev": "ts-node src/server.ts",
"build": "next build",
"start": "NODE_ENV=production ts-node src/server.ts",
"lint": "next lint",
"prettier:format": "prettier --write .",
"prettier:check": "prettier --check .",
"component-tests": "cypress run --component",
"e2e:chrome": "cypress run --e2e --browser chrome",
"e2e:edge": "cypress run --e2e --browser edge",
"commitlint": "commitlint --from develop --to HEAD",
"check-updates": "npx npm-check-updates -u",
"test": "jest",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"prepare": "if [ "$SKIP_HUSKY" = "true" ]; then echo 'Skipping husky'; else husky; fi"
},
"private": true,
"dependencies": {
"@braintree/sanitize-url": "7.1.0",
"@mdi/js": "7.4.47",
"@mdi/react": "1.6.1",
"@newrelic/next": "0.10.0",
"@serwist/next": "9.0.11",
"classnames": "^2.5.1",
"dayjs": "1.11.13",
"kafkajs": "2.2.4",
"mssql": "11.0.1",
"newrelic": "12.9.0",
"next": "15.1.2",
"next-auth": "4.24.11",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-toastify": "11.0.2",
"sass": "^1.83.0",
"sharp": "0.33.5",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1"
},
"devDependencies": {
"@chromatic-com/storybook": "^3.2.3",
"@commitlint/cli": "19.6.1",
"@commitlint/config-conventional": "19.6.0",
"@eslint/js": "9.17.0",
"@storybook/addon-essentials": "^8.4.7",
"@storybook/addon-interactions": "^8.4.7",
"@storybook/addon-onboarding": "^8.4.7",
"@storybook/blocks": "^8.4.7",
"@storybook/nextjs": "^8.4.7",
"@storybook/react": "^8.4.7",
"@storybook/test": "^8.4.7",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.1.0",
"@types/jest": "^29.5.14",
"@types/jira-client": "7.1.9",
"@types/mssql": "9.1.5",
"@types/newrelic": "9.14.6",
"@types/node": "22.10.2",
"@types/react": "19.0.2",
"@types/react-dom": "19.0.2",
"@types/sharp": "0.31.1",
"cypress": "13.17.0",
"dotenv": "16.4.7",
"eslint": "9.17.0",
"eslint-config-next": "15.1.2",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-cypress": "4.1.0",
"eslint-plugin-storybook": "^0.11.1",
"husky": "^9.1.7",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jira-client": "8.2.2",
"npm-check-updates": "^17.1.11",
"prettier": "3.4.2",
"serwist": "9.0.11",
"start-server-and-test": "2.0.9",
"storybook": "^8.4.7",
"ts-node": "^10.9.2",
"typescript": "5.7.2",
"typescript-eslint": "8.18.1"
},
"browserslist": [
">0.3%",
"last 2 versions",
"not dead"
],
"eslintConfig": {
"extends": [
"plugin:storybook/recommended"
]
}
}
Checked the documentation for custom servers but couldn’t find anything specific to this issue. Searched online for similar issues but didn’t find an exact match. Has anyone faced this issue or something similar? What could be causing this SyntaxError?
Thank you in advance!