CalcSnippets Search
CLI 4 min read

`lsof -i` Is the Fastest Way to Answer “What Is Using This Port?” on Mac

A practical lsof guide for developers on macOS who need to find which process owns a port, understand the output, and stop guessing when localhost refuses to start.

The real reason people hate port errors: not because ports are complicated, but because the error message usually tells you what failed, not who is causing it. lsof -i closes that gap fast.

Why this command matters

When npm run dev, uvicorn, docker compose, or flutter run says a port is already in use, most developers waste time in the wrong order. They restart the app. Then they restart the terminal. Then they restart the machine. Only after that do they ask the useful question: what process is actually holding the port?

lsof means “list open files,” and on Unix-like systems network sockets count as open files too. That is why the command is so useful for port debugging.

The version many developers need most often is:

lsof -i :3000

That asks for open network files related to port 3000. If something is listening there, lsof will usually tell you the command name, process ID, user, and connection details.

The output is less mysterious than it looks

People see columns and panic, but most of the time you only need a few:

  1. COMMAND tells you what process owns it
  2. PID tells you what you could inspect or terminate
  3. USER tells you whether it belongs to you or another account
  4. NAME usually shows the port binding

That is enough to answer the real debugging question: is this your dev server, another tool, a container helper, or a zombie process left behind by a failed run?

The command you will probably use most

If you want only listening processes and not every connection touching the port:

lsof -nP -iTCP:3000 -sTCP:LISTEN

This version is more surgical. -nP avoids slow hostname and service-name resolution, which makes output cleaner and faster. -iTCP:3000 narrows the search to TCP on port 3000, and -sTCP:LISTEN focuses on listeners instead of active client connections.

That is important because many “port already in use” problems are specifically about a process listening on the port, not every socket that ever talked to it.

A good debugging flow

Use a sequence like this:

  1. run lsof -nP -iTCP:3000 -sTCP:LISTEN
  2. identify the command and PID
  3. decide whether the process is legitimate or stale
  4. either stop it normally or change your app port intentionally

That last step matters. Killing processes is not always the right answer. Sometimes the other service is supposed to be there. Good debugging is not only about removing friction. It is about understanding whether the conflict is accidental or expected.

Why kill -9 is too often the first bad reflex

The internet is full of advice that goes straight to:

kill -9 <pid>

Yes, that works sometimes. It is also a good way to hide whether the process had a clean shutdown path, whether it will immediately restart, or whether you just killed something you still needed.

A better habit is:

kill <pid>

and only escalate if the process ignores a normal termination signal. The goal is not dramatic force. The goal is a clean development machine.

Common real-world causes

Port conflicts are often one of these:

  1. a previous dev server crashed but never released cleanly
  2. Docker or another container tool started a background service
  3. a second copy of the same project is already running
  4. a different app chose the same common port

Notice how none of those are fixed by guessing. They are fixed by identifying the owner first.

Why this belongs in muscle memory

Once you get used to it, lsof -i stops feeling like a system-admin trick and starts feeling like basic developer hygiene. Localhost work gets much less frustrating when you can answer port questions in ten seconds instead of improvising restarts for ten minutes.

Final recommendation

If a local service refuses to start because a port is busy, do not treat the error as a mystery. Run lsof -nP -iTCP:<port> -sTCP:LISTEN, identify the owner, and decide intentionally whether to stop it or move around it. Port debugging gets much calmer once you stop asking the shell to be psychic.

Sources

Keep reading

Related guides