The error Error: listen EADDRINUSE: address already in use :::3000 means another process is already using the port your Node.js app wants. It’s one of the most common errors during development. Here’s every way to fix it.
📋 Table of Contents
- What Causes This Error
- Fix 1: Find and Kill the Process (macOS/Linux)
- Fix 2: Find and Kill the Process (Windows)
- Fix 3: Use a Different Port
- Fix 4: Handle the Error Gracefully
- Fix 5: Implement Graceful Shutdown (Prevents the Problem)
- Fix 6: Use nodemon for Clean Restarts
- Reusable Kill-Port Script
- Frequently Asked Questions
- Conclusion
What Causes This Error
- A previous server instance didn’t shut down cleanly and still holds the port
- Another application is using the same port (another dev server, database)
- A crashed process left a zombie holding the port
- You started your server twice
Fix 1: Find and Kill the Process (macOS/Linux)
# Find the process using port 3000
lsof -i :3000
# COMMAND PID USER FD TYPE DEVICE NODE NAME
# node 12345 you 20u IPv6 ... TCP *:3000 (LISTEN)
# Kill it by PID
kill -9 12345
# Or do it in one command
kill -9 $(lsof -ti :3000)
# Kill all node processes (nuclear option)
killall -9 node
Fix 2: Find and Kill the Process (Windows)
# Find the process using port 3000
netstat -ano | findstr :3000
# TCP 0.0.0.0:3000 0.0.0.0:0 LISTENING 12345
# Kill it by PID
taskkill /PID 12345 /F
# PowerShell one-liner
Stop-Process -Id (Get-NetTCPConnection -LocalPort 3000).OwningProcess -Force
Fix 3: Use a Different Port
// Make the port configurable via environment variable
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log("Server running on port " + PORT);
});
// Then run with a different port:
// PORT=3001 node server.js
Fix 4: Handle the Error Gracefully
const server = app.listen(PORT);
server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
console.error("Port " + PORT + " busy. Trying " + (PORT + 1));
server.listen(PORT + 1); // fall back to next port
} else {
throw err;
}
});
Fix 5: Implement Graceful Shutdown (Prevents the Problem)
The root cause is often a server that does not release the port on exit. Add graceful shutdown handlers:
const server = app.listen(PORT, () => {
console.log("Server running on port " + PORT);
});
function shutdown(signal) {
console.log(signal + " received. Closing server...");
server.close(() => {
console.log("Server closed. Port released.");
process.exit(0);
});
setTimeout(() => {
console.error("Forced shutdown");
process.exit(1);
}, 10000);
}
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT')); // Ctrl+C
Fix 6: Use nodemon for Clean Restarts
npm install --save-dev nodemon
# package.json
{
"scripts": {
"dev": "nodemon server.js"
}
}
# nodemon cleanly restarts and releases ports between reloads
npm run dev
Reusable Kill-Port Script
# kill-port.sh
#!/bin/bash
PORT=${1:-3000}
PID=$(lsof -ti :$PORT)
if [ -n "$PID" ]; then
echo "Killing process $PID on port $PORT"
kill -9 $PID
else
echo "No process on port $PORT"
fi
# Usage: ./kill-port.sh 3000
Frequently Asked Questions
Q: Why does the port stay in use after I stop my app?
A: Usually because the process was killed abruptly without releasing the socket, or a child process still holds it. Graceful shutdown handlers prevent this.
Q: What does ::: in ‘:::3000’ mean?
A: IPv6 notation for “all interfaces” (like 0.0.0.0 in IPv4). Your server binds to all network interfaces on port 3000.
Q: Can two apps share the same port?
A: No — only one process can bind to a port on an interface at a time. Use different ports or a reverse proxy (nginx) to route by path/domain.
Q: How do I avoid this in Docker?
A: Each container has its own network namespace, so conflicts only happen at host mapping. Map different host ports: -p 3001:3000.
Q: Is killall node safe?
A: It kills ALL Node.js processes — fine in development, but careful if you have other Node apps you don’t want stopped.
Conclusion
EADDRINUSE means the port is already taken. Quick fix: find the process with lsof -ti :PORT and kill it. Permanent fix: add graceful shutdown handlers so your server always releases the port on exit, and use nodemon in development for clean restarts. Making the port configurable via process.env.PORT also sidesteps conflicts instantly.
📚 You might also like
🔗 Share this article




✍️ Leave a Comment