Skip to content

Port 3000 Already in Use? One Command Tells You Who Started It (witr)

EADDRINUSE on port 3000? witr traces the process listening on a port back to what launched it — parent, working dir, socket. The one-line install, the usage, and the classic lsof + kill fallback.

Port 3000 Already in Use? One Command Tells You Who Started It

You run npm run dev, and the terminal spits back Error: listen EADDRINUSE: address already in use :::3000. Something is on port 3000 — but what? You didn’t start anything. Or you did, three terminals ago, and forgot. This is the single most common “why won’t my app start” moment for every developer, and there is now a one-command answer to it.

The tool: witr

witr (“what is running”) answers who is on a port — and, crucially, what started them. Instead of just handing you a bare process ID, it traces the whole story: the process listening on the port, its parent process, the working directory it was launched from, and the socket it’s holding. It’s a small, fast, dependency-light DevOps debugging tool with thousands of stars on GitHub, and it turns “kill the mystery process” into “understand the mystery process.”

Install (one line)

curl -fsSL https://raw.githubusercontent.com/pranshuparmar/witr/main/install.sh | INSTALL_PREFIX=$HOME/.local bash

Installing into $HOME/.local keeps it in your user space — no sudo, nothing touching system directories. Make sure $HOME/.local/bin is on your PATH (most shells already have it; if not, add export PATH="$HOME/.local/bin:$PATH" to your .zshrc).

Find who’s on port 3000

witr --port 3000

That’s it. witr prints the process holding the port and then walks the tree back to its origin — so instead of an anonymous node PID, you see the parent shell, the exact folder the server was started in, and the socket details. Suddenly “some node process” becomes “oh, that’s the old dev server I left running in the deployu-lms-app folder yesterday.” Now you can kill it knowing what it was, or just switch back to that terminal.

Knowing your tools is step one — building real systems is the skill

DeployU puts you on real cloud servers and real AWS accounts, where debugging ports, processes and services is the daily job — not a video.

One honest gotcha about the syntax

witr uses --port specifically for ports. If you pass a bare number — witr 3000 — it treats that as a process name to search for, not a port. So the habit to build is: always type --port when you mean a port. It’s a small thing, but it’s exactly the kind of detail that costs ten confused minutes the first time you hit it, so learn it once here.

The classic fallback: lsof + kill

witr is the friendly version, but you should also know the raw tools it’s built on top of — because they’re on almost every machine, no install required.

lsof -i :3000

lsof (“list open files”) lists everything holding port 3000, with the PID in the second column. Once you have that PID:

kill -9 <PID>

kill -9 sends SIGKILL — the un-ignorable “stop now” signal. Use it when a normal kill <PID> (which sends the gentler SIGTERM) doesn’t work. A one-liner that combines both:

kill -9 $(lsof -t -i :3000)

lsof -t prints just the PID, feeding it straight into kill. This is the muscle-memory move for “I don’t care what it is, get it off my port.”

When to reach for which

  • witr --port 3000 when you want to understand what’s running — which folder, which parent, which project. This is the DevOps mindset: know before you kill.
  • lsof -i :3000 + kill -9 when you already know it’s a stray dev server and just want the port back, fast.

Both belong in your toolkit. The next time EADDRINUSE stops you cold, you won’t restart your whole machine or guess — you’ll run one command and know exactly who’s on the port and what started them.

From debugging ports to shipping services

DeployU turns terminal fluency into deployable, portfolio-ready skills — real servers, real AWS, real projects that get you hired.