# EADDRINUSE: Address Already in Use — How to Free the Port

```text
Error: listen EADDRINUSE: address already in use :::3000
```

Only one process can listen on a given port at a time. This error means something already has port 3000 — usually an earlier copy of your own server that never shut down. The fix is two steps: find the process, then stop it.

## Find what's using the port

**macOS and Linux**:

```bash
lsof -i :3000
```

```text
COMMAND   PID  USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
node    48213  alex   23u  IPv6  0x8f…      0t0  TCP *:3000 (LISTEN)
```

The `PID` column is what you need. On Linux without `lsof`, `ss` shows the same:

```bash
ss -ltnp | grep :3000
```

**Windows** (Command Prompt):

```bat
netstat -ano | findstr :3000
```

The last column is the PID. In PowerShell:

```powershell
Get-NetTCPConnection -LocalPort 3000 | Select-Object OwningProcess
```

## Stop it

```bash
kill 48213          # ask it to exit cleanly
kill -9 48213       # force it, if it ignores the first
```

Or in one line, on macOS and Linux:

```bash
kill $(lsof -ti :3000)
```

On Windows:

```bat
taskkill /PID 48213 /F
```

Before you kill anything, check the command name. If it isn't yours — a database, another app, a system service — change your app's port instead.

## Why it keeps happening

- **A dev server still running in another terminal**, or a background job you forgot. Close it properly with Ctrl+C rather than closing the window.
- **A crashed run left a child process behind.** Tools that spawn your server (nodemon, concurrently, npm scripts) can leave an orphaned process if they're killed abruptly.
- **Your code calls `listen()` twice** — for example, the app module starts the server and your test setup starts it again.
- **A Docker container publishes the port.** `docker ps` shows it in the PORTS column; stop the container or map it elsewhere.
- **Port 5000 on macOS.** Since macOS Monterey, the AirPlay Receiver listens on ports 5000 and 7000. Use another port, or turn off AirPlay Receiver in System Settings → General → AirDrop & Handoff.

## Make your server fail clearly and exit cleanly

Read the port from the environment so you can move it without editing code, and turn the crash into a readable message:

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

server.on("error", (err) => {
  if (err.code === "EADDRINUSE") {
    console.error(`Port ${PORT} is already in use. Stop the other process or set PORT.`);
    process.exit(1);
  }
  throw err;
});

// Release the port when you press Ctrl+C or the process is told to stop
for (const signal of ["SIGINT", "SIGTERM"]) {
  process.on(signal, () => server.close(() => process.exit(0)));
}
```

The signal handlers matter most under process managers and containers, which send `SIGTERM` and wait for a clean exit before forcing one.

## The same error elsewhere

The message varies, but the cause is the same:

- Python: `OSError: [Errno 98] Address already in use` (Linux) or `[Errno 48]` (macOS)
- Go: `listen tcp :8080: bind: address already in use`
- Docker: `Bind for 0.0.0.0:8080 failed: port is already allocated`
- nginx: `bind() to 0.0.0.0:80 failed (98: Address already in use)`

`lsof -i :<port>` finds the culprit for all of them. And if the server *is* running but the browser still can't reach it, the problem is somewhere else — for a reverse proxy, start with [502 Bad Gateway](/blog/fix-502-bad-gateway-nginx).
