PortPeek on the command line
Port-conflict pain starts in the terminal — an EADDRINUSE and a guess. portpeek is a tiny standalone companion to the tray app: list what's listening, inspect a port, and free it, without leaving the shell.
01Install
The PortPeek installer includes the CLI and can add it to your user PATH during setup.
- Download and run the PortPeek installer from the latest release.
- Choose Yes when setup asks to add PortPeek to PATH.
- Open a new PowerShell or Windows Terminal window, then run
portpeekfrom any folder.
portpeek.exe from the release assets and place it in a folder already on PATH. The installer is the recommended option.PS> portpeek --version portpeek <installed-version>
02List listening ports
Run portpeek with no arguments for a table of your dev ports. System/OS ports are hidden and UDP is off by default — same scoping as the app's toolbar.
PS> portpeek PORT PROTO ADDRESS PID PROCESS MEM 5173 tcp * 14820 vite 48 MB 5432 tcp 127.0.0.1, ::1 5140 postgres 2 MB 9277 tcp 127.0.0.1 9784 warp 102 MB
One row per listener, not per socket. A process bound to both IPv4 and IPv6 shows once, with every bind address in ADDRESS; * means a wildcard bind (0.0.0.0/::) — listening on every interface.
Include more with -a/--all and --udp
Add system-owned ports, UDP listeners, or both:
PS> portpeek --all --udp PORT PROTO ADDRESS PID PROCESS MEM 135 tcp * 1084 svchost 1 MB 445 tcp * 4 System 0 MB 5173 tcp * 14820 vite 48 MB 5353 udp * 1520 svchost 2 MB 41641 udp 100.114.54.3 9076 tailscaled 17 MB
03Inspect a port
Pass a port number to see everything about whatever's holding it — process, PID, memory, uptime, executable, project folder, and the full launch command.
PS> portpeek 5173 port: 5173 (tcp) address: * process: vite pid: 14820 memory: 48 MB uptime: 22m executable: C:\Program Files\nodejs\node.exe project: C:\Projects\shop command: node node_modules/vite/bin/vite.js --host
If nothing's listening, it exits non-zero with error: nothing is listening on port 5173 — handy in scripts.
04Free a busy port
The headline job: portpeek free <port> stops the process holding a port so you can restart your server.
PS> portpeek free 5173 Freed port 5173 (stopped pid 14820).
It runs the same safeguards as the app's Stop button — it refuses ports owned by protected system processes rather than risk your machine:
PS> portpeek free 445 error: port 445 is owned by a protected system process; refusing to stop it
free stops the process immediately, with no confirmation prompt. It only touches your own processes; kernel/system PIDs and protected names are always refused.05Flags
Global flags work on any command.
| Flag | Effect |
|---|---|
-a, --all | Include system/OS-owned ports in the listing (hidden by default). |
--udp | Include UDP listeners (TCP-only by default). |
--json | Print machine-readable JSON instead of the table — for scripts and pipelines. |
-h, --help | Show usage for the command. |
-V, --version | Print the version. |
06Scripting with --json
Every command takes --json. The listing and single-port output emit one object per listener (camelCase fields, the app's PortItem shape) with the bind addresses collected into an addresses array, so you can pipe it straight into jq, CI, or your own tooling. The CLI leaves url, framework, and the favicon fields null — those come from the app's detection step, which the CLI skips.
PS> portpeek 5173 --json [ { "id": "tcp|5173|14820", "port": 5173, "addresses": ["0.0.0.0", "::"], "protocol": "tcp", "pid": 14820, "processName": "node.exe", "displayName": "vite", "memoryMb": 48.3, "uptimeSeconds": 1320, "command": "node node_modules/vite/bin/vite.js --host", "executablePath": "C:\\Program Files\\nodejs\\node.exe", "workingDirectory": "C:\\Projects\\shop", "url": null, "faviconUrl": null, "cachedFaviconPath": null, "framework": null, "isSystemPort": false } ]
free --json reports which PIDs it stopped and any errors, so automation can react:
PS> portpeek free 5173 --json { "port": 5173, "freedPids": [14820], "errors": [] }
07Good to know
- The CLI talks to the same Windows scanning and terminate code as the tray app — the numbers match what you see in the UI.
- It skips framework and favicon detection (those run inside the app), so a port lookup won't label a server "Next.js" the way the GUI does — it stays fast and dependency-free.
- Commands exit non-zero on failure (nothing listening, protected process, kill error), so
&&chains and CI steps behave. - Prefer clicking? Everything here is in the tray app too.