The Error
Error: listen EADDRINUSE: address already in use :::3000
at Server.setupListenHandle [as _listen2] (node:net:1739:16)
at listenInCluster (node:net:1787:12)
at Server.listen (node:net:1875:7)
at Function.listen (/app/node_modules/express/lib/application.js:635:24)
Port 3000 is taken. Node.js tried to bind a listener there, found something already running, and bailed out. Two processes cannot share the same TCP port โ so one of them has to go.
Root Cause
Three common culprits:
- A previous server instance crashed or you force-closed the terminal window. The Node.js process kept running in the background, still holding port 3000.
- Something else already claimed that port โ a different Node.js app, Webpack dev server, a Python Flask app, you name it.
- You restarted too fast. The OS needs a moment (usually a few seconds) to reclaim a port after the old process exits. Hit Ctrl+C and immediately ran
npm start? You might have beaten the clock.
Step-by-Step Fix
Step 1: Find the process using the port
On macOS / Linux:
lsof -i :3000
Example output:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 1234 alice 23u IPv6 12345 0t0 TCP *:3000 (LISTEN)
That PID column โ 1234 here โ is what you need in the next step.
Prefer ss or netstat? Those work too:
# Using ss
ss -tlnp | grep :3000
# Using netstat
netstat -tlnp | grep :3000
On Windows (Command Prompt or PowerShell):
netstat -ano | findstr :3000
Example output:
TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 5678
The last number (5678) is the PID.
Step 2: Kill the process
On macOS / Linux:
kill -9 1234
Swap 1234 for the actual PID you found. Or skip the lookup entirely and do it in one shot:
kill -9 $(lsof -ti :3000)
On Windows (run as Administrator):
taskkill /PID 5678 /F
Step 3: Restart your Node.js server
node app.js
# or
npm start
# or
npx ts-node src/index.ts
Alternative Fix: Use a Different Port
Maybe the process on port 3000 is intentional โ another app you need running. No problem. Just move your server elsewhere.
In your app code:
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Or set the port at startup without touching your code:
PORT=3001 node app.js
On Windows:
set PORT=3001 && node app.js
Fix for nodemon / Development Watch Mode
Seeing this error after every file save? nodemon is probably restarting the process before the OS has reclaimed the port. A 1-second delay usually fixes it:
# nodemon.json
{
"delay": 1000
}
If it's really stuck, nuke all Node processes and start fresh:
# macOS / Linux โ kill all Node processes
pkill -f node
# then restart
npm run dev
Verify the Fix
Run the same lookup command after killing the process:
# macOS / Linux
lsof -i :3000
# Windows
netstat -ano | findstr :3000
No output means the port is free. Start your server โ it should come up clean.
Want to confirm it's actually responding? Run a quick curl:
curl http://localhost:3000
# or open http://localhost:3000 in a browser
Tips to Avoid This Error
- Ctrl+C beats closing the terminal โ closing the window often orphans the Node.js process. It keeps running, keeps holding the port. Ctrl+C sends SIGINT and shuts things down properly.
- Read the port from an env variable โ hardcoding
3000works until it doesn't.process.env.PORT || 3000lets you switch ports with a single env var, no code edits needed. - Add a graceful shutdown handler in production โ this lets the server release the port cleanly on exit:
process.on('SIGTERM', () => {
server.close(() => {
console.log('Server closed');
process.exit(0);
});
});
- Using PM2? Mind the old instance โ
pm2 restart apphandles overlap automatically. For a fresh start, runpm2 stop allfirst to make sure nothing is still clinging to your port.

