Skip to content

Port 3000 is already in use: find and stop what holds it

By 4 min read

You run npm run dev and get EADDRINUSE: address already in use :::3000. Something is holding the port, and it's usually a dev server you forgot about. Maybe it's from a terminal tab you closed yesterday, or a script that spawned a child and then died.

This is how I find and stop it, first with the tools that ship with the Mac, then with the way I do it now.

The terminal way

Ask which process is listening on the port:

lsof -nP -iTCP:3000 -sTCP:LISTEN

The flags matter. -n and -P skip DNS and service-name lookups, which makes it fast. -iTCP:3000 -sTCP:LISTEN keeps only the listening socket, so you don't get every client connected to it.

You'll get a table. The PID column is what you want:

COMMAND   PID  USER   FD   TYPE  NODE NAME
node    48213  tom    23u  IPv6  TCP  *:3000 (LISTEN)

Then stop it:

kill 48213

Plain kill sends SIGTERM, which lets the process clean up. Give it a second and run the lsof line again. If it's still there, kill -9 48213 ends it without asking, so use it second, not first.

Where this goes wrong

The two-step routine works, but I kept running into the same few problems:

  • The PID tells you nothing. node is not an answer. Which project is that? I have several. Killing the wrong one means losing a running server in another window.
  • A single node can be a tree. Dev tools spawn workers, watchers and helper processes. You kill the parent and a child keeps the port. You kill the child and the parent starts another.
  • IPv4 and IPv6 are separate listeners. localhost:3000 can be bound on ::1 and 127.0.0.1 by different processes. Checking only one hides the other.
  • It's not always yours. On macOS, AirPlay Receiver has used port 5000 and 7000, and I've seen people blame their own code for hours before finding that out. Check the process name before you kill anything.

To get the project, you can look up the process's working directory:

lsof -a -p 48213 -d cwd

That prints the folder the process was started from, which is usually enough to recognise the project. It's a third command, and I never remembered the flags.

How I do it in Binnacle

I built Binnacle partly because I was tired of this routine. It's a Mac activity monitor that lives in the menu bar and opens into a full-window console I call the Command Deck. It has two ways to deal with a stuck port.

The ⌘K command line. Open the Deck, press ⌘K and type:

port 3000

It shows the process holding the port. If that's the one you want gone:

kill port 3000

It asks you to confirm before it does anything. That confirmation is deliberate: every quit in Binnacle asks first, because I've closed the wrong thing too many times.

The Projects page. If you don't know which port you're after, this page lists your dev servers grouped by project folder. Each row shows the ports it's listening on, its memory use and how long it has been idle, with a Stop button. The folder grouping answers the "which project is that?" question without a cwd lookup. The idle time helps with the forgotten ones. A server that has been idle since yesterday morning is probably not one you need.

One implementation detail, in case you care: Binnacle reads ports through libproc, a macOS system library, so it doesn't shell out to lsof and parse the text.

A short checklist

Whichever tool you use, this order saves me time:

  1. Find the listener on the port, not just any socket that mentions it.
  2. Work out which project it belongs to before you stop it.
  3. Try a normal stop (SIGTERM) first. Escalate only if it stays.
  4. Run the check again to confirm the port is actually free.
  5. If the same port is busy again a minute later, something is restarting it. Look at the parent process, a file watcher or a process manager, instead of killing it over and over.

Is it worth paying for?

If you hit this once a month, the lsof and kill pair is fine, and you shouldn't install anything. Save the one-liner as a shell alias and move on.

Binnacle makes more sense if you run several dev servers at once, or if the port is only one of the questions you ask. The same Deck covers things like which app is behind a spinning fan, or what's using the memory. It has a 14-day trial with everything unlocked. After that it's $9 once, and the menu bar readouts stay free. The Deck, including the Projects page and ⌘K, needs the license.

It needs macOS 14 or later. It collects no telemetry, and its only network calls are license activation and update checks.

If you try the port commands and one of them gets it wrong on your machine, tell me which setup you were running. Those reports are the most useful thing I get.

Tom Shafer

Builds Laravel sites and small Mac apps at Shafer LLC, and writes here about what he learns doing it. About Shafer LLC

Get the newsletter.

What’s new, now and then. No spam; unsubscribe in one click.