Skip to content
OnDevKit
Error Fixes

EADDRINUSE address already in use: 4 safe fixes

Fix "Error: listen EADDRINUSE: address already in use" in Node.js. Find the process using the port on Windows, stop it, or pick another port.

Published · 4 min read
On this page

Quick answer

Another program is already using that port, usually an old copy of your own server. On Windows, run netstat -ano | findstr :3000, then taskkill /PID <pid> /F. Or start your app on another port with the PORT variable.

Error: listen EADDRINUSE: address already in use means your Node.js server tried to open a port that another program is already using. Most of the time that "other program" is an old copy of your own server that never stopped. This guide shows how to find it on Windows, stop it safely, and make your app handle a busy port on its own. Every command below was run on Windows 11 with Node.js 26.

What does EADDRINUSE address already in use mean?

A port is a numbered door on your computer, like 3000. Only one program can listen on a port at a time. When your server calls listen(3000) and something already owns port 3000, Node.js throws this error and your app stops:

node:events:505
    throw er; // Unhandled 'error' event
    ^

Error: listen EADDRINUSE: address already in use :::3000
    at Server.setupListenHandle [as _listen2] (node:net:2390:16)
    ...
  code: 'EADDRINUSE',
  errno: -4091,

:::3000 is the IPv6 way of writing "every address, port 3000". The Node.js docs call EADDRINUSE "one of the most common errors raised when listening" (Node.js net docs).

Diagram of EADDRINUSE address already in use: an old server still holds port 3000, so the new server cannot listen and crashes.

Why does it happen?

The usual causes, from most to least common:

  • An old server is still running. You closed the editor or the terminal tab, but the Node process kept going in the background.
  • You started the app twice. For example, npm run dev in two terminals.
  • Another app uses the same port. Many tools default to 3000, 5173, 8080 or 5000.
  • A crashed watcher left a process behind. Tools that restart your server on save can occasionally leave an old copy running.

Fix 1: Find and stop the process on Windows

First find which process owns the port. In Command Prompt or PowerShell:

netstat -ano | findstr :3000

The last column is the process ID (PID):

  TCP    0.0.0.0:3000      0.0.0.0:0      LISTENING       17596
  TCP    [::]:3000         [::]:0         LISTENING       17596

Check what that PID is before you stop it, so you don't close something important:

Get-Process -Id 17596

If it's node, stop it:

taskkill /PID 17596 /F

Windows replies SUCCESS: The process with PID 17596 has been terminated. Now start your server again.

Three steps to free a busy port on Windows: find the PID with netstat, check it with Get-Process, stop it with taskkill.

The PowerShell one-liner

PowerShell can find and stop it in one go. This only targets the process listening on that port:

Stop-Process -Id (Get-NetTCPConnection -LocalPort 3000 -State Listen).OwningProcess -Force

On macOS or Linux

Use lsof to list the process on the port, then stop it by PID (lsof manual):

lsof -i :3000
kill <PID>

Fix 2: Use a different port

If you need both programs running, give your app another port. Read it from the PORT environment variable so you can change it without editing code:

const PORT = Number(process.env.PORT) || 3000;
server.listen(PORT, () => console.log(`Listening on http://localhost:${PORT}`));

Then start it on a free port. In PowerShell:

$env:PORT = 3001; node server.js

In bash (macOS, Linux, Git Bash):

PORT=3001 node server.js

Fix 3: Handle EADDRINUSE in your code

By default the error crashes your app with an "Unhandled 'error' event". Listen for the server's error event instead, and try the next port. This is a tested version of the approach in the Node.js docs:

const http = require('node:http');

const server = http.createServer((req, res) => res.end('ok'));
let port = Number(process.env.PORT) || 3000;

server.on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
    console.error(`Port ${port} is busy, trying ${port + 1}...`);
    port += 1;
    server.listen(port);
  } else {
    throw err;
  }
});

server.on('listening', () => console.log(`Listening on http://localhost:${port}`));
server.listen(port);

With port 3000 busy, it prints:

Port 3000 is busy, trying 3001...
Listening on http://localhost:3001
Comparison of a server that crashes on EADDRINUSE with one that handles the error event and moves to the next free port.

Use this for local development. In production, a fixed port is usually better, so a busy port should stop the app and show up in your logs.

Fix 4: Stop it from coming back

  • Stop servers with Ctrl+C in the terminal before you close it.
  • Run your dev server in one terminal only. If your editor has a "Run" button, don't also start it by hand.
  • If a file watcher keeps leaving copies behind, update it, or stop it with Ctrl+C before you close the window.

Still seeing EADDRINUSE address already in use?

  • netstat shows nothing, but the error continues: your app may be calling listen() twice, for example once in app.js and again in a test file. Search your code for .listen(.
  • The PID belongs to System or a service: a Windows service owns that port. Pick another port (Fix 2) instead of stopping it.
  • Different error, EACCES: that's a permissions problem, not a busy port. Ports below 1024 often need admin rights; use a higher port.

Setting up a Windows dev machine? See how to set up a GitHub SSH key on Windows. To understand when listen() callbacks run, try these Node.js event loop interview questions.