Every developer knows this one:
Error: listen EADDRINUSE: address already in use :::3000 Something is already using port 3000. Maybe yesterday's dev server, maybe a Docker
container, maybe a process from a terminal tab you closed. Finding out takes a
different incantation on every OS:
lsof -i :3000 -sTCP:LISTEN # macOS / Linux netstat -ano | findstr :3000 # Windows, then look up the PID ss -ltnp 'sport = :3000' # Linux, the modern way Then you kill -9 a PID and hope it wasn't something important. Or you run
npx kill-port 3000, which does the same kill -9 without even showing you what it hit.
I built portcheck to make this
boring: the same answer on every OS, a safe way to fix it, and the fix right where you
hit the error.
Try it without installing anything
$ npx portcheck-cli 3000 PORT PROTO STATUS PID PROCESS USER 3000 tcp in-use 42379 node alice $ npx portcheck-cli kill 3000 About to terminate: PID 42379 node (port 3000), started by npm (4200) ← zsh (900), in my-shop Proceed? [y/N] y PID PROCESS RESULT DETAIL 42379 node terminated Before it stops anything, it shows you what it is, who started it (npm ← zsh),
and which project it belongs to. Then it waits for your yes.
Why it's safer than kill -9
- It stops processes gently. It sends
SIGTERMfirst so the server can clean up, and only forces it after 5 seconds.kill -9gives it no chance, which is how you end up with stale lock files and half-written caches. - It refuses to stop the wrong things. PID 1, your own shell, and system processes such as
launchd,systemdandsvchost.exeare off-limits, so a typo can't take down your machine. - It understands containers and WSL. If Docker publishes the port, portcheck names the container and tells you
docker stop web, instead of killing Docker's proxy (which would take down every container at once).
The dev servers you forgot
My favourite command came out of my own mess: node processes from projects I'd stopped
working on days ago, still holding ports and memory.
$ portcheck servers PID PROCESS PROJECT PORTS UPTIME 41852 node my-shop 5173,24678 2d 6h 51230 python3 api 8000 1h 30m It lists your own processes that listen on a port and run inside a project folder,
oldest first. portcheck servers --older-than 1d --stop cleans them up, asking first.
Fix it where the error happens
In VS Code, when a command in the terminal fails because its port is taken, the
extension
pops up:
⚠ Port 3000 is already in use by node (pid 41852). [Fix…]
The menu offers to stop it and re-run your command, or re-run on the next free
port. It recognises errors from Node, Vite, Next.js, Python (Flask, Django, uvicorn),
Rails, Spring Boot, Go, .NET, PHP and more, including Python's [Errno 48] Address, which doesn't even say which port. It's also on
already in use
Open VSX for Cursor,
VSCodium and Windsurf.
In Vite, which normally just moves to the next port without telling you why, a
two-line plugin says who holds your port and adds a k shortcut to stop it and restart
on the original port:
// vite.config.ts import portcheck from "portcheck-cli/vite"; export default { plugins: [portcheck()] }; Port 5173 is in use, trying another one... portcheck: port 5173 is in use by node (pid 41852), started by npm (41850) ← zsh (900). portcheck: press k + enter to stop node and restart on port 5173 In Next.js, Express or any Node server, a preload hook adds the same explanation to
the crash, without changing how it fails:
NODE_OPTIONS="--require=portcheck-cli/register" next dev In the browser, the extension for
Edge
and Firefox
puts a badge on every localhost tab: node, pyth, java, or a red off when nothing
is listening. "This site can't be reached" finally tells you something useful.
In your AI coding assistant, portcheck mcp is an MCP server, so Claude Code, Cursor
or Copilot can check and free ports themselves when your dev server fails. Stopping a
process is marked destructive, so they ask you first:
claude mcp add --scope user portcheck -- npx -y portcheck-cli mcp There's also a JetBrains plugin, a Neovim plugin, and a menu bar app.
How it's built
portcheck is a single static Go binary for macOS, Linux and Windows. On macOS it reads
sockets straight from libproc without cgo, about ten times faster than running lsof.
Every integration above is a thin client of the same binary and its versioned --json
output, so the logic and the safety checks live in one place.
It's MIT licensed, and releases are signed with cosign and ship SBOMs and build
provenance.
Get it
npx portcheck-cli 3000 # no install brew install roystondwork-dev/tap/portcheck # macOS, Linux npm install -g portcheck-cli # any OS pipx install portcheck-tool # any OS On Windows, Scoop works too (see the install guide).
- Repo: https://github.com/roystondwork-dev/portcheck
- Docs: https://roystondwork-dev.github.io/portcheck/
- Fixes for your exact error (Node, Python, Docker, databases, macOS, Windows, Linux): https://roystondwork-dev.github.io/portcheck/fix/
Full disclosure: I built portcheck with a lot of help from an AI coding assistant
(Claude Code). It's new, so I'd really like to hear what breaks, and which tools' "port in
use" errors it should learn next.

