Portpal
A native desktop dashboard that shows every port your machine is listening on, kills the process blocking it in one click, and visualizes how your services are actually connected.
Repository Health
Technical Analysis
Portpal is a Tauri-based desktop app built to end the EADDRINUSE: address already in use ritual. Instead of dropping into a terminal to run lsof or netstat, grepping for a PID, and typing kill -9, Portpal keeps a live dashboard of every listening port on your machine — process name, PID, framework, and originating project — and lets you kill or restart any of them with a single click.
Beyond simple port listing, Portpal builds a D3.js-powered network topology map that traces active TCP connections back to the listening ports and processes that own them, so you can see at a glance how your frontend, API, and database containers are actually talking to each other. A background watcher thread polls port state every two seconds, logs start/stop events with timestamps, records lightweight traffic history per port, and drives a system tray icon that changes color (green/yellow/red) the moment a port conflict appears — all without keeping the main window open.
Under the hood it uses sysinfo plus the OS-native lsof (macOS/Linux) or netstat (Windows) to enumerate listening sockets and cross-reference them against process metadata, then walks up the directory tree from each process’s working directory looking for package.json, Cargo.toml, go.mod, or .git to label which project a port belongs to. It ships as a single cross-platform binary via Tauri 2, so there’s no Node runtime or Electron overhead — just a lightweight Rust backend and a React 19 + TypeScript UI.
What You Get
- Real-time port dashboard - every listening TCP port with process name, PID, protocol, detected framework, and the project directory it was launched from.
- One-click kill and restart - terminate a blocking process instantly, or restart it in its original working directory if Portpal captured its start command.
- Interactive D3.js port map - a force-directed graph showing which services are actually connected to each other, built by correlating active connections back to listening ports and shared PIDs.
- System tray traffic light - a debounced tray icon (green/yellow/red) and tooltip that surface port conflicts and active dev-port counts without opening the main window.
- Historical event log and traffic sparklines - every port start/stop is timestamped and kept in a rolling log, with per-port connection-count history rendered as inline sparkline charts.
- Automatic framework and project detection - built-in recognition for common dev ports (React, Vite, Angular, Django, Postgres, Redis, MongoDB, Tauri, and more) plus project-name inference from
package.json/Cargo.toml/go.mod/.git.
Common Use Cases
- Clearing a stuck dev server port - a crashed
npm run devprocess is still holding port 5173; open Portpal, find it, and kill it in one click instead of typinglsof -i :5173. - Untangling a multi-service local stack - a developer running a frontend, API, and database together uses the port map to confirm which container is actually talking to which port.
- Spotting port conflicts at a glance - the system tray icon turns red the moment two processes try to bind the same port, before the terminal error even scrolls past.
- Auditing what’s running before a demo - before a screen-share, a developer opens the dashboard to see every open port and framework running on their machine and shuts down anything unnecessary.
- Restarting a killed server without retyping the command - Portpal remembers the original start command and working directory, so a mistakenly-killed dev server can be relaunched with the restart button.
Under The Hood
Architecture
Portpal runs as a Tauri 2 application split into a Rust backend (scanner.rs, connections.rs, logger.rs, tray.rs) and a React frontend, coordinated from main.rs, which registers six Tauri commands (get_ports, kill_process, restart_process, get_port_graph, get_port_events, get_port_traffic) and spawns a background watcher thread from tray.rs that polls port state every two seconds, updates a global lazy_static event logger, and emits ports-updated/port-events/tray-state-changed events straight to the webview. The frontend’s App.tsx is a large single component that owns all page state (dashboard, ports, traffic, services, logs, map) and reacts to those emitted events rather than polling on its own, which keeps the UI in sync with negligible overhead but leaves page-level components un-split from the top-level file. Notably, the project’s lib.rs still contains the unused default Tauri-template greet command and is never invoked by main.rs’s own entry point — dead scaffolding left over from tauri create.
Tech Stack
The backend is Rust on Tauri 2 with tray-icon and image-png features, sysinfo for process introspection, regex and serde/serde_json for parsing and serialization, lazy_static and once_cell for global state, window-vibrancy for native window effects, and libc for POSIX signal handling (SIGTERM then SIGKILL) on macOS/Linux. Port scanning itself shells out to platform-native tools — lsof -iTCP -sTCP:LISTEN on macOS/Linux, netstat -ano on Windows, and ss -tnp for established connections on Linux — rather than reimplementing socket enumeration in Rust. The frontend is React 19 with TypeScript, bundled by Vite 7, using D3.js v7 for the force-directed port-map visualization and vanilla CSS for a custom glassmorphism theme, with no external state-management or UI-component library.
Code Quality
No test files or test framework exist anywhere in the repository, and the codebase leans on .unwrap() and .expect() in several places — process-list Mutex locks, the netstat/lsof subprocess calls in scanner.rs — which will panic the watcher thread rather than degrade gracefully if a native command is missing or a lock is poisoned. Error handling elsewhere is more deliberate, with Result<(), String> return types and map_err conversions on the kill/restart commands. TypeScript interfaces mirror the Rust Serialize structs reasonably closely, and naming is consistent (snake_case in Rust, camelCase in TS), but there’s no linter or formatter configuration and no CI step that runs tests — the one GitHub Actions workflow only builds release artifacts.
What Makes It Unique
Most port-killer utilities stop at listing PIDs; Portpal’s distinguishing feature is reconstructing a live service topology from raw connection data — it correlates every active TCP connection back to the listening ports that own each side, including ephemeral-port connections where a client’s random source port has to be traced back to a sibling listening port owned by the same PID, then renders the result as an interactive, physics-based D3 graph. Combined with the debounced system-tray traffic-light state machine and rolling per-port traffic sparklines, it reads more like a lightweight local observability tool than a simple kill-port script, even though its core detection logic still leans on standard OS command-line tools rather than raw socket APIs.
Self-Hosting
Licensing Model MIT licensed — all features available with no restrictions or license keys required. Portpal is a local desktop utility with no cloud service, subscription tier, or hosted component.
Related Apps
deepseek-harness
AI Agents · AI Development · Developer Tools
An open-source, plugin-based agent harness from DeepSeek AI that runs coding and automation agents across web, desktop, CLI, and SDK surfaces.
Ollama
AI Development · Developer Tools
Run Llama, Gemma, DeepSeek, and other open LLMs on your own machine with one command and an OpenAI-compatible API.
Firecrawl
AI Development · Developer Tools
Turn any website into clean, LLM-ready data with a single API call — no proxy headaches, no scraping complexity.