See what's listening on your local ports. Fast. Zero deps. Reads /proc directly on Linux, falls back to lsof on macOS/BSD.
$ portcheck
port proto command pid address
80 tcp nginx 1923 0.0.0.0
443 tcp nginx 1923 0.0.0.0
3000 tcp node 28471 127.0.0.1
5432 tcp postgres 1923 127.0.0.1
8000 tcp uvicorn 2728014 127.0.0.1
You started a dev server two windows ago. You started another one in this window. They both bound to :3000. You don't remember which is which. The fix is lsof -i :3000, but lsof is slow on machines with many file descriptors and the output is full of fields you don't need. netstat -tlnp was deprecated five distros ago. ss -ltnp is fast but its column alignment was last touched in the kernel 3.x era.
portcheck is what those commands would look like if you wrote them today: column-aligned, sorted by port, no sudo for your own processes, instant on a laptop with 50K open fds.
npm install -g @v0idd0/portcheck# All listening ports
portcheck
# Filter to a single port
portcheck 443
# Filter to a range
portcheck 8000-9000
# JSON for piping
portcheck --json | jq '.[] | select(.command == "node")'| tool | speed on 50K fds | sudo for self | output legibility | macOS support |
|---|---|---|---|---|
| portcheck | <50ms | no | aligned, sorted by port | via lsof fallback |
lsof -i -P -n |
2-3s | yes (for others) | dense, hard to scan | yes |
ss -ltnp |
<100ms | yes (for cmd) | terse columns | no |
netstat -tlnp |
varies | sometimes | 1990s formatting | deprecated |
If you regularly investigate ports across machines you don't own (oncall, debugging others' processes), lsof -i is still the canonical answer. For your own laptop and your own processes, portcheck is faster typing and faster reading.
Why doesn't it need sudo? On Linux it parses /proc/<pid>/net/tcp and /proc/<pid>/cmdline for processes you own, which doesn't require elevation. To see ports owned by other users, run with sudo — same rule as lsof.
Does it show UDP? Yes when you ask: portcheck --proto udp or --proto all. Default is TCP because that's what people actually search for.
What about systemd-managed sockets that no process holds open yet? Not visible until the activated process binds. That's a kernel-level signal portcheck deliberately doesn't try to surface — systemctl list-sockets is the right tool there.
Why no docker integration? Containers running on your host do appear under their PID. If you want container-aware port mapping, docker ps shows the published-port column already.
import { list, filterRange, format } from '@v0idd0/portcheck';
const all = list();
const webPorts = filterRange(all, '80-443');
console.log(format(webPorts));- Pipe to
awkfor ad-hoc filters —portcheck --json | jq '.[] | select(.address == "0.0.0.0")'finds anything bound to a public interface, useful when you wonder why your firewall rule isn't doing what you thought. - In docker-compose dev workflows — run
portcheckon the host to confirm published ports actually landed; container-internal ports won't appear (they live in the container's net namespace), which is itself a useful signal. - As a teardown helper —
portcheck --json | jq '.[] | select(.command == "node") | .pid' | xargs killis the no-ceremony version of "kill all my orphaned dev servers". Use with care.
This is one tool out of many — see from-the-studio.md for the full lineup of vøiddo products (other CLI tools, browser extensions, the studio's flagship products and games).
MIT.
Built by vøiddo — a small studio shipping AI-flavoured products, free dev tools, Chrome extensions and weird browser games.