PannKs
UsefulTools & notes

Library

OverviewShort links
Prompts5
How To4
  • Free a Port a Dead Dev Server Still Holds
  • Ship a Fix Users Can't See (Service Worker Edition)
  • Stop the Page Jumping While It Loads
  • Truncate Text Without Breaking the Layout
← All How To

Free a Port a Dead Dev Server Still Holds

EADDRINUSE when nothing is running — how to find the real owner of a port and kill it, without guessing at PIDs.

tags
clinodedebugging
updated
2026-08-17

Loading…

Older →Ship a Fix Users Can't See (Service Worker Edition)
Buy Me A Coffee

v.4.0.0 | Created By Next.JS 16.3.1

Pann Kaansadich © 2026

The symptom

You start the dev server and get:

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

…except nothing is running. A previous run crashed, or its parent shell died, and the child process kept the socket. It may not even answer requests any more — a wedged next-server can hold port 3000 while curl gets nothing back.

Find the actual owner

lsof -nP -iTCP:3000 -sTCP:LISTEN
  • -nP skips DNS and port-name lookups, so it returns instantly
  • -sTCP:LISTEN filters out clients that merely connected to the port

Look at the command before you kill anything — the PID that holds the socket is often a child, and killing only the child leaves the parent to respawn it:

ps -p "$(lsof -nP -iTCP:3000 -sTCP:LISTEN -t)" -o pid=,ppid=,command=

Kill it

kill $(lsof -nP -iTCP:3000 -sTCP:LISTEN -t)

Plain kill sends SIGTERM, which lets the server close its sockets and flush its build cache. Reach for kill -9 only if it is still there a few seconds later — SIGKILL skips cleanup, and for a bundler that can mean a corrupt cache directory on next start.

The version worth aliasing

freeport() { lsof -nP -iTCP:"$1" -sTCP:LISTEN -t | xargs -r kill; }

Then freeport 3000. The -r matters: without it, xargs runs kill with no arguments when the port is already free, and you get a confusing usage error instead of silence.

Or just move

If the other process is something you actually want running, don't fight it:

npm run dev -- -p 3100

Most dev servers take a port flag after --. Two servers, two ports, no detective work.

Why it happens

A terminal that closes without sending SIGHUP to its process group, a crashed parent, a debugger detaching — any of these can orphan the listener. On macOS the socket also lingers briefly in TIME_WAIT after a clean exit; that one clears itself in seconds and is not worth killing anything over.