Port 3000 is already in use on Mac: find and stop the process

Find what holds port 3000 with lsof, stop it with kill, or do both in one click.

You start a dev server and get this error:

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

Another process already listens on port 3000. Find it first. Then decide if you stop it or move your server to another port.

Find the process on port 3000

lsof -nP -iTCP:3000 -sTCP:LISTEN

The output looks like this:

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
node    48213 me     22u  IPv6 0x1234      0t0  TCP *:3000 (LISTEN)
  • -nP skips DNS and port name lookups. Without -P, lsof can print a service name instead of 3000.
  • -iTCP:3000 selects TCP sockets on port 3000.
  • -sTCP:LISTEN keeps only the listener. Without it you also see every client connected to that port.

The second column is the PID. If the output is empty, the process may belong to another user. Run the same command with sudo.

Check what it is before you stop it

ps -p 48213 -o pid,ppid,command

The command column often shows the project path. Look at ppid too. If the parent is npm, pnpm or nodemon, the parent can start the server again after you stop it.

Stop it

kill 48213

kill sends SIGTERM. The process can clean up and exit. Run the lsof command again to check that the port is free. If the process is still there after a few seconds, use kill -9 48213. That sends SIGKILL, which the process cannot catch. See how to kill the process on a port for the trade-offs.

To find and stop in one line:

kill $(lsof -ti tcp:3000 -sTCP:LISTEN)

-t prints only PIDs. If nothing listens, kill prints a usage message and does nothing else.

Common reasons the port is taken

  • A dev server from an earlier session still runs in another terminal tab, or an editor or coding agent started it and left it.
  • A Docker container publishes the port. Check with docker ps --filter publish=3000.
  • A second copy of your own project runs from another folder.

macOS itself uses ports 5000 and 7000 for AirPlay Receiver. That is a common clash for Flask and other tools, but not for port 3000. To free them, turn off AirPlay Receiver in System Settings.

Or use another port

Most tools take a flag or an environment variable:

PORT=3001 npm run dev
npm run dev -- --port 3001   # Vite
npx next dev -p 3001         # Next.js

Do it in one click with Portfox

Portfox is a menu bar app that lists every TCP listener on your Mac. It names the service from the process, not the port number, so it shows Next.js or Vite and the project folder, not just node.

  • Click the Portfox icon in the menu bar and find the row with :3000.
  • Check the project name and the badges. An Orphaned badge means the process that started the server has exited.
  • Click Stop.

Stop sends SIGTERM to the process that started the server, for example pnpm dev, not only the inner node process. That prevents the wrapper from starting it again. Force Stop sends SIGKILL, and only when you ask for it.

Install Portfox with Homebrew:

brew install --cask xergic/tap/portfox

No Homebrew? Download the app from portfox.kandera.cz/download. Portfox needs macOS 15 or later and an Apple Silicon Mac. It is free and open source (MIT).