whoport - who is using my port? | Claire Nord
//-->
whoport - who is using my port?
Written on
August<br>11th,<br>2026<br>by
Claire Nord
Recently I’ve been running swarms of coding agents on my laptop.<br>At some point I started to feel like my laptop is haunted, being puppeted by many beings out of my control.
For example, I’ll go to develop on jep, and run into:
% npm run dev
> dev<br>> react-router dev
Port 3000 is in use, trying another one...<br>➜ Local: http://localhost:3001/<br>➜ Network: use --host to expose<br>➜ press h + enter to show help
Hey! Who is using localhost:3000 ?!
How to use whoport
whoport is my new small, sharp tool to solve this. Pass in a port and it’ll tell you what command (and therefore what path -> project + worktree) is using it:
% whoport 3000<br>PORT PID COMMAND<br>3000 61981 node ~/conductor/workspaces/echo/rome-v3/target/debug/api
whoport can look up multiple ports at once:
% whoport 3000 5432<br>3000 61981 node ~/conductor/workspaces/echo/rome-v3/target/debug/api<br>5432 688 /usr/local/opt/postgresql/bin/postgres -D /usr/local/var/postgres
Check it out here on GitHub 🐈⬛ https://github.com/cmnord/whoport
After you’ve found the process using your port, you can obviously kill -9 it 🔪 or otherwise shuffle ports around.
Why? ps + grep falls apart with coding agents
My previous tool for this was good ol’ ps with some text searches.<br>ps (“process status”) lists information about processes running on your<br>computer.<br>The typical command is ps aux to list a ll running processes.<br>I used this in combination with a search tool like grep (or ag or, lately,<br>rg) like so:
Atuin v18.19.0 : exit, : edit, : run, : inspect history count: 18631<br>Search │ Inspect
3 111ms 3mo ago ps aux | rg 'expo start'<br>2 101ms 3mo ago ps aux | rg 'dev:'<br>1 128ms 2mo ago ps aux | rg 'expo'<br>> 123ms 2mo ago ps aux | rg 'expo '<br>[ GLOBAL ] 'ps aux'<br>ps aux | rg 'expo '
shoutout to atuin
ps aux | rg 'npm ' worked when I had a hunch about the name of the command<br>and I could search them.<br>But now I have like 20-50 node processes running on my computer at any time…
% ps aux | rg 'node' | wc -l<br>53<br>% ps aux | rg 'npm ' | wc -l<br>28
translation: count how many running processes begin with 'node ' or 'npm '
Moreover, the commands agents kick off are completely unreadable…
% ps aux | rg 'npm ' | head -n 2<br>cnord 21752 0.1 0.4 446355296 149152 ?? S 8:02PM 0:00.22 node /Users/cnord/.nvm/versions/node/v22.22.3/bin/pnpm -C packages/editor exec vitest run --environment jsdom src/note/index.test.ts src/plugins/doc-change-listener.test.ts
↳ Okay, seems like it’s running Vitest, that’s fine.
cnord 6522 0.0 0.0 435341104 5136 ?? S 7:46PM 0:00.01 /usr/bin/open -n -W -o target/debug/example-dev.stdout.log --stderr target/debug/example-dev.stderr.log --env RANDOM_CONFIG_VAR=foo --env VITE_API_URL=https://api.example.com --env YOUR_SECRET_KEY=hunter2 --env YOUR_RANDOM_OAUTH_CLIENT_ID=hunter2 --env PATH=./my/whole/hecking/path/list/.bin:/......... target/debug/Example.app
↳ What in the world is happening in this 3,000-character command which has my whole env and PATH in it???
which of you is hogging my port?
whoport under the hood
whoport glues together ~two other tools: stalwart ps, plus lsof to list open files.
The core lsof command is:
lsof -t -nP -iTCP:"$port" -sTCP:LISTEN
Brief explanation of the command:
flag(s)<br>meaning
-t
t erse output: PIDs only, no header
-nP<br>skip DNS resolution and service name lookups
-iTCP:$port<br>only TCP sockets using this port (local or remote)
-sTCP:LISTEN<br>only TCP sockets in listen state
So with just this command we can get a newline-separated list of process IDs (PIDs).
whoport turns this into a comma-separated list to hand to ps.
Heroic ps returns, instead filtering by PID instead of search on the commands!
% ps -o pid=61981,command=COMMAND -p 61981<br>61981 COMMAND<br>61981 node ~/conductor/workspaces/echo/rome-v3/target/debug/api
So now I know that the rome-v3 echo worktree is using the port!<br>And from there I can *ahem* terminate it or move aside.<br>localhost:3001 isn’t so bad, anyway.
Filling out your tool belt
I keep little scripts like this in my dotfiles repo, which documents my favorite terminal commands and setup across laptops and machines. 🛠️
You should too! Some influential blogs on this topic:
Your Dotfiles Are Meant to be Forked, Zach Holman
Managing Your Dotfiles, Anish Athalye
Read more about tiny personal programs here:
Some tiny personal programs I’ve written, Julia Evans
And to learn more about the command line, ps, etc., I highly recommend The Missing Semester of Your CS Education.
Happy coding :)
Feel free to share!
You may also enjoy:
Jep! - play Jeopardy! with friends online
The Five Types of Sports