portview
See what's on your ports, then act on it.
A diagnostic-first port viewer for Linux. No more lsof -i :3000 | grep LISTEN incantations. One command shows you what's listening, who owns it, how long it's been running, and offers to kill it if you want.
~930 KB single binary. Zero runtime dependencies.
Install
One-liner (downloads pre-built binary):
|
Homebrew:
Cargo (build from source):
Manual: grab the binary from Releases, chmod +x, drop in PATH.
Usage
Show all listening ports
$ portview
╭──────┬───────┬───────┬──────┬──────────┬─────────┬────────┬─────────────────────────────────────╮
│ PORT │ PROTO │ PID │ USER │ PROCESS │ UPTIME │ MEM │ COMMAND │
├──────┼───────┼───────┼──────┼──────────┼─────────┼────────┼─────────────────────────────────────┤
│ 3000 │ TCP │ 48291 │ mark │ node │ 3h 12m │ 248 MB │ next dev │
│ 5432 │ TCP │ 1203 │ pg │ postgres │ 14d 2h │ 38 MB │ /usr/lib/postgresql/16/bin/postgres │
│ 6379 │ TCP │ 1198 │ redis│ redis │ 14d 2h │ 12 MB │ redis-server *:6379 │
│ 8080 │ TCP │ 51002 │ mark │ python3 │ 22m │ 45 MB │ uvicorn main:app --port 8080 │
╰──────┴───────┴───────┴──────┴──────────┴─────────┴────────┴─────────────────────────────────────╯
Inspect a specific port
$ portview 3000
Port 3000 (TCP) — node (PID 48291)
Bind: *:3000
Command: next dev
User: mark
Started: 3h 12m ago
Memory: 248 MB
CPU time: 14.3s
Children: 3
State: LISTEN
Kill process 48291? [y/N]
Search by process name
$ portview python
╭──────┬───────┬───────┬──────┬─────────┬────────┬───────┬──────────────────────────────────╮
│ PORT │ PROTO │ PID │ USER │ PROCESS │ UPTIME │ MEM │ COMMAND │
├──────┼───────┼───────┼──────┼─────────┼────────┼───────┼──────────────────────────────────┤
│ 8000 │ TCP │ 51002 │ mark │ python3 │ 22m │ 45 MB │ uvicorn main:app --port 8000 │
│ 8080 │ TCP │ 51340 │ mark │ python3 │ 5m │ 32 MB │ python3 -m http.server 8080 │
╰──────┴───────┴───────┴──────┴─────────┴────────┴───────┴──────────────────────────────────╯
Kill directly
Watch mode (live refresh)
The display refreshes every second. Ctrl+C exits cleanly.
JSON output
|
Show all connections (not just listening)
Custom colors
Table columns are colored by default. Customize with the PORTVIEW_COLORS environment variable:
PORTVIEW_COLORS="port=red,pid=magenta,command=bright_cyan"
Available columns: port, proto, pid, user, process, uptime, mem, command
Available colors: red, green, blue, cyan, yellow, magenta, white, bold, dimmed, bright_red, bright_green, bright_blue, bright_cyan, bright_yellow, bright_magenta, bright_white, none
Defaults: port=cyan, proto=dimmed, pid=yellow, user=green, process=bold, uptime=dimmed, mem=dimmed, command=white
Use --no-color to disable all colors.
What it shows
For each listening port:
| Field | Source |
|---|---|
| Port & protocol | /proc/net/tcp, /proc/net/udp |
| PID | inode→pid mapping via /proc/*/fd/ |
| Process name | /proc/<pid>/comm |
| Full command | /proc/<pid>/cmdline |
| User | /proc/<pid>/status → getpwuid |
| Uptime | /proc/<pid>/stat starttime + btime |
| RSS memory | /proc/<pid>/status VmRSS |
| CPU time | /proc/<pid>/stat utime + stime |
| Child count | /proc/<pid>/task/<pid>/children |
Everything is read directly from procfs. No shelling out to lsof, ss, or netstat.
Why not...
| Tool | Issue |
|---|---|
lsof -i :3000 |
Different flags per OS, cryptic output, slow |
ss -tlnp |
Powerful but unreadable, no uptime/memory info |
fkill-cli |
Node.js dependency, kill-first not diagnostic-first |
killport |
Rust but kill-only, no inspection |
procs |
General process viewer, not port-centric |
portview is diagnostic-first: understand what's on your ports, then optionally act.
Building from source
Limitations
- Linux only (reads
/procdirectly). macOS/Windows support would require platform-specific backends. - Needs read access to
/proc/<pid>/fd/for inode→pid mapping. Some processes owned by other users may requiresudo.
License
MIT