Ports & dev servers

“Address already in use” on Mac: find it, free it, or move

Every framework words it differently, but it’s the same problem: another process is already listening on that port. On a Mac the culprit is usually a dev server you forgot, an orphan from a closed terminal, Docker, or the AirPlay Receiver on 5000 and 7000.

Step 1: find who has the port

lsof -nP -iTCP:3000 -sTCP:LISTEN

Swap in your port number. The COMMAND and PID columns tell you what it is. If you get nothing back, try again with sudo, because a root-owned process is hidden from normal users. For a full walkthrough of reading the result, see what’s using a port on my Mac.

Then either stop it (kill <PID>, details in how to kill a process on a port) or run your server on another port. The rest of this page covers the error as each tool prints it.

Node.js and Express

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

The :::3000 means Node tried to listen on every IPv6 and IPv4 address. Most often the previous npm run dev is still running in another tab, or it survived a closed terminal as an orphan. Change the port for one run:

PORT=3001 npm run dev

That works for Express apps that read process.env.PORT, Next.js and most starters. For Next.js you can also pass next dev -p 3001.

Vite (and SvelteKit, Astro, Nuxt on Vite)

Vite doesn’t fail by default. It prints Port 5173 is in use, trying another one... and moves to 5174, 5175 and so on. That’s how people end up with four copies of the same app on four ports. If you set strictPort: true (or pass --strictPort), it stops instead:

error when starting dev server:
Error: Port 5173 is already in use

Pick the port explicitly with vite --port 5180, or set server.port in vite.config.ts.

Rails and Puma

Two different messages show up here. The first is a real port conflict:

Address already in use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE)

The second is a leftover PID file after a crash, even when nothing is listening:

A server is already running (pid: 48211, file: tmp/pids/server.pid).

Check whether that PID is alive with ps -p 48211. If it isn’t, delete tmp/pids/server.pid and start again. To use another port: bin/rails server -p 3001.

Python: Flask, Django, http.server

OSError: [Errno 48] Address already in use

Django’s runserver reports Error: That port is already in use. Move it with python manage.py runserver 8001. For the built-in file server, python3 -m http.server 8001.

Flask defaults to port 5000, which collides with AirPlay on a Mac.

macOS AirPlay Receiver on 5000 and 7000

Since macOS Monterey, the AirPlay Receiver listens on ports 5000 and 7000. lsof shows the owner as ControlCenter, and opening localhost:5000 in a browser returns a blank 403 Forbidden instead of your Flask app. Flask’s own error message even points at it.

You have two options:

  1. Turn it off: System Settings › General › AirDrop & Handoff › AirPlay Receiver. The port frees immediately.
  2. Keep AirPlay and move your app: flask run --port 5001.

Killing ControlCenter doesn’t help: macOS restarts it within a second. The port 5000 and port 7000 pages list the other tools that default there.

Docker

Error response from daemon: ... Bind for 0.0.0.0:5432 failed: port is already allocated

Either another container already published that port, or something on your Mac (often a Homebrew Postgres or Redis) is using it. Check both:

docker ps --filter publish=5432
lsof -nP -iTCP:5432 -sTCP:LISTEN

Stop the other container, run brew services stop postgresql@16 for a Homebrew service, or map the container to a different host port with -p 5433:5432.

Go, Rust and everything else

listen tcp :8080: bind: address already in use

Same fix: find the listener with lsof, stop it or pick another port. The error text changes; the cause doesn’t.

Why it keeps happening

If you see this error every day, it’s usually one of three habits:

  • Closing the terminal window instead of pressing Ctrl+C. Some dev servers ignore the hang-up and keep running with no terminal. These are orphans, covered in finding orphaned Node processes.
  • AI agents starting servers. Claude Code, Codex and Cursor often run npm run dev to test their work and leave it running. See cleaning up after Claude Code.
  • Background services you installed once. brew services list shows what Homebrew starts at login.

Seeing it before the error

Stat Space shows every listening port in your menu bar, with the framework, project folder and the launcher that started it (a terminal, an editor, an agent, launchd or Docker). The Ports tab search takes a number and tells you whether that port is free before you start a server. The CLI does the same check: statspace port 3000.

Questions

Why does it say address in use when nothing shows in Activity Monitor?

Activity Monitor doesn’t show ports. A server can be a plain node or python process with no window, or a Docker container behind com.docker.backend. Use lsof -nP -iTCP:<port> -sTCP:LISTEN to see the real owner.

What is Errno 48?

On macOS, error number 48 is EADDRINUSE. Python prints it as OSError: [Errno 48] Address already in use. On Linux the same error is number 98.

Can two servers share a port if one uses IPv4 and one uses IPv6?

Yes, a server on 127.0.0.1:3000 and another on [::1]:3000 can both run, which is confusing because localhost may reach either. If two dev servers seem to answer on one port, check lsof for both an IPv4 and an IPv6 listener.

Get started

Know what your Mac is doing, without adding to it.

Free, no account. Pro is $9.99 once for the first 100 buyers.