A port by itself does nothing.
A port only matters when a process opens it and waits for connections. That process is called a listener.
When you run a dev server, database, proxy, model server, or background service, it may become a listener.
node listening on 127.0.0.1:3000
python listening on 127.0.0.1:8000
redis listening on 127.0.0.1:6379
ollama listening on 127.0.0.1:11434
The listener is the thing you actually need to understand.
The mental model
The address gets you to the building. The port gets you to the door. The listener is the person waiting behind the door.
If nobody is waiting, the request fails.
localhost exists
port 3000 exists as a number
but no listener exists
That produces errors like:
ERR_CONNECTION_REFUSED
Connection refused
Failed to connect
The machine is reachable. The door is just empty.
See every listener
On macOS, run:
lsof -nP -iTCP -sTCP:LISTEN
You may see output like:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 48217 you 21u IPv4 ... TCP 127.0.0.1:3000 (LISTEN)
python3 48302 you 4u IPv4 ... TCP 127.0.0.1:8000 (LISTEN)
redis-ser 11844 you 6u IPv4 ... TCP 127.0.0.1:6379 (LISTEN)
Do not panic if the list is long. A modern Mac runs many background services.
Inspect one listener
To inspect port 3000:
lsof -nP -iTCP:3000 -sTCP:LISTEN
The important fields are:
| Field | Meaning |
|---|---|
COMMAND | The process name, such as node, python3, or redis-server |
PID | The process ID, a temporary number assigned by the system |
USER | The user account running it |
NAME | The address and port it is listening on |
Then inspect the process itself:
ps -p <PID> -o pid,ppid,user,stat,comm,args
Replace <PID> with the actual number.
Example:
ps -p 48217 -o pid,ppid,user,stat,comm,args
This often reveals whether the listener came from npm, pnpm, python, uvicorn, docker, an IDE, or a background service.
Listener is not the same as connection
A listener waits for new connections.
An established connection is an active conversation that already happened.
In lsof, you may see both:
LISTEN
ESTABLISHED
For “what owns this port?” you usually care about LISTEN.
That is why the command includes:
-sTCP:LISTEN
It filters out ordinary active connections and shows only the processes waiting for new ones.
Why Localhost Explorer shows process details
A plain port number is not enough.
You need to know:
- What process owns the port.
- What command started it.
- What folder it came from.
- Whether it is bound to
localhostor every interface. - Whether killing the PID will actually stop it.
That is the difference between “I killed a random process” and “I stopped the correct dev server.”
Common mistake
Do not assume the process name tells the whole story.
node could be a frontend app, a backend app, a test runner, a package tool, or an IDE helper.
python3 could be FastAPI, Django, a script, a notebook, or a temporary file server.
The listener tells you there is a process. The command and folder tell you what it really is.