Every port on your Mac, traced to the project that opened it
Not just node on :3000. Stat Space shows it’s next dev from ~/code/acme-web, started by Claude Code 41 minutes ago, and whether your whole network can reach it.
What’s on :3000? Who started it?
Every listening port, traced to its project folder and whatever launched it: a terminal, your editor, an AI agent, launchd or Docker. Servers reachable from your network get flagged by name, with what that means and a one-click fix.
- Process node · next dev pid 48211 · 640 MB
- Project acme-web ~/code/acme-web · Next.js 15
- Shell zsh pid 48190
- Launcher Claude Code session ended 6m ago left behind
- Process node · prisma studio pid 48377 · 210 MB
- Project acme-web ~/code/acme-web · Next.js 15
- Shell zsh pid 48190
- Launcher Claude Code session ended 6m ago left behind
- Process node · vite pid 51022 · 188 MB
- Project docs-site ~/code/docs-site · Vite 6
- Shell zsh pid 50998
- Launcher Terminal window 2, tab 1
- Process com.docker.backend pid 1882
- Container db image postgres:16 Pro
- Runtime OrbStack mapped 5432 → 5432
- Launcher Docker running 3d
http-server is open to your network. :8080 is listening on every interface, so other devices on your network can connect. Bind it to 127.0.0.1 to keep it on this Mac, or stop it from Needs attention.
- Process node · http-server pid 60417 · 54 MB
- Project demo ~/code/demo
- Shell zsh pid 60380
- Launcher Cursor integrated terminal
$ statspace ports PORT PROCESS PROJECT PID LAUNCHER UPTIME BIND :3000 next dev acme-web 48211 Claude Code 41m 127.0.0.1 :5173 vite docs-site 51022 Terminal 2h 127.0.0.1 :5432 postgres:16 db 1882 Docker 3d 127.0.0.1 :8080 http-server demo 60417 Cursor 6m 0.0.0.0 exposed 1 port is reachable from your network (bound to 0.0.0.0 or a LAN address). $ statspace kill 3000 Stop next dev (pid 48211) on :3000? [y/N] y Stopped next dev.
Project and framework
Each port shows its working folder and the framework it’s running (Next.js, Vite, Rails, Django, Postgres and more), so five
nodeprocesses stop looking the same.Who started it
The parent chain is walked back to the launcher: Terminal, iTerm, Ghostty, VS Code, Cursor, Claude Code, Codex, launchd or Docker.
Exposed-to-LAN warning
Servers bound to
0.0.0.0instead of127.0.0.1are flagged, because anyone on the café Wi-Fi can reach them.One click from done
Open in the browser, copy the URL, show a QR code for your phone, reveal the folder, or stop it. Stopping always asks first.
From the terminal
statspace ports,statspace port 3000andstatspace kill 3000, with--jsonfor scripts.Docker containers (Pro)
Ports published by Docker are mapped to the container and image behind them instead of
com.docker.backend.
Why lsof isn’t enough
lsof -iTCP -sTCP:LISTEN -n -P is the classic answer, and it works. But it gives you a command name and a PID. When you run several projects, a handful of agents and a Docker stack, “node, 48211” doesn’t tell you which one to stop. Stat Space resolves the rest: the working directory becomes a project, the parent chain becomes a launcher, and the start time becomes an uptime.
Built to stay out of the way
The port list is built from proc_pidinfo socket data, not by shelling out to lsof, and it only refreshes while the Ports tab, a pinned Home card or the menu bar item needs it. With the popover closed, Stat Space idles under 0.3% CPU.
Questions
Does it show ports held by root, like a launchd daemon?
If you ask for them. Stat Space runs as you, so by default it lists the listeners your account owns: dev servers, Docker-published ports, Homebrew services and your own launch agents. Turn on Settings › General › System ports and the Ports tab gets a System section: press Load, enter your password once, and it runs a read-only lsof to list root-owned listeners too. The list is a snapshot that never refreshes on its own, and statspace ports --system prints it.
Will it ask for my admin password to stop something?
Only for a third-party launch daemon in the System section, and only after you confirm. Stat Space names exactly what will happen, asks for your password, then runs launchctl bootout system/<label>. It never kills a root process directly and never edits or deletes the plist, so the daemon may start again at next boot. Apple's own processes are view-only. Everything else is stopped only if you own it.
Why does a server come back after I stop it?
Something is restarting it: usually a launch agent with KeepAlive, brew services, a process manager like pm2 or nodemon, or Docker’s restart policy. Stop it at that level, for example brew services stop postgresql or launchctl bootout gui/$(id -u)/<label>.
Know what your Mac is doing, without adding to it.
Free, no account. Pro is $9.99 once for the first 100 buyers.