$ npm run dev
Error: listen EADDRINUSE: address already in use :::3000
You've seen this a thousand times. Something crashed, a zombie process is holding your port, and you're Googling lsof -i :3000 | grep LISTEN | awk '{print $2}' | xargs kill -9 again.
Stop.
$ portctl fix 3000
portctl identifies the process (Next.js dev server), confirms it's safe to kill, sends a graceful shutdown, verifies it's gone, and tells you exactly how to restart. One command. Two seconds.
The Problem
Every developer hits "port already in use" multiple times a week. The usual fix:
# The old way: hope you don't kill the wrong thing
This is fragile, dangerous, and tells you nothing. You're blindly killing processes without knowing what they are, whether they're safe to stop, or how to restart them.
The Solution
portctl is a developer environment recovery tool. It doesn't just kill ports. It understands what's running, assesses whether it's safe to stop, chooses the right shutdown strategy, and tells you how to restart.
$ portctl 3000
⚡ Port 3000 in use
→ Next.js (PID 81106)
→ running for 7m 21s
→ memory 42.9 MB
→ cwd /Users/abhishek/project/web
→ detected Next.js (95% confidence)
→ 🛡 safe to kill
📂 Detected project: Next.js
→ dev command: npm run dev
→ default port: 3000
Install
Homebrew
Shell script (macOS / Linux)
|
Cargo
npm
From source
&&
Demo
See everything on your ports
$ portctl scan
⚡ 5 active ports
PORT PROCESS PID SERVICE MEMORY UPTIME USER
────────────────────────────────────────────────────────────────────────────────
3000 node 81106 Next.js 42.9 MB 7m 17s abhishek
3898 Code Helper (Plugin) 34290 Python 20.2 MB 3h 12m abhishek
5237 Code Helper (Plugin) 34073 Python 20.1 MB 3h 12m abhishek
5932 Code Helper (Plugin) 61773 Python 57.5 MB 58m 35s abhishek
42050 OneDrive Sync Serv.. 36643 Unknown 14.4 MB 3d 1h abhishek
Fix a port conflict in one command
$ portctl fix 3000
⚡ Port 3000 in use
→ Next.js (PID 81106)
→ detected Next.js (95% confidence)
→ 🛡 safe to kill
🛡 SAFE Next.js is a dev server -- safe to kill and restart
⚙ strategy: Graceful (SIGTERM + wait)
Fix port 3000 using Graceful (SIGTERM + wait)? [Y/n] y
• Sending SIGTERM to PID 81106
• Waiting up to 5s for graceful shutdown
• Verified: PID 81106 has exited
✔ Killed safely port 3000 is now free
Restart: cd /Users/abhishek/project/web && npm run dev
Fix and auto-restart in one shot
$ portctl fix 3000 --run "npm run dev"
✔ Killed safely port 3000 is now free
🚀 Restarting: npm run dev
Error to recovery in under 3 seconds.
See ports grouped by role
$ portctl group --dev
⚡ 4 active ports in 2 groups
⚙ Frontend (2)
────────────────────────────────────────────────────────────────────────────
3000 node 81106 Next.js 42.9 MB 7m 21s abhishek
3898 Code Helper (Plugin) 34290 Python 20.2 MB 3h 12m abhishek
⚙ Backend (2)
────────────────────────────────────────────────────────────────────────────
5237 Code Helper (Plugin) 34073 Python 20.0 MB 3h 12m abhishek
5932 Code Helper (Plugin) 61773 Python 57.5 MB 58m 39s abhishek
Auto-diagnose your dev environment
$ portctl doctor
🩺 2 issues found
1. Idle process Code Helper (PID 34290) at 0.0% CPU [auto-fixable]
→ Idle Code Helper on port 3898 -- consider killing to free resources
2. Idle process Code Helper (PID 34073) at 0.0% CPU [auto-fixable]
→ Idle Code Helper on port 5237 -- consider killing to free resources
⚙ Run portctl doctor -y to auto-fix 2 issues
Before vs After
| Scenario | Before | After |
|---|---|---|
| "Port 3000 in use" | lsof -i :3000 | awk ... | xargs kill -9 |
portctl fix 3000 |
| "What's on my ports?" | lsof -iTCP -sTCP:LISTEN (wall of text) |
portctl scan (clean table) |
| "Is it safe to kill?" | Google the process name | portctl tells you automatically |
| "How do I restart?" | Check package.json, guess the command | portctl shows the restart hint |
| "Zombie processes piling up" | Manually hunt each one | portctl doctor -y (auto-fix) |
| "Which port is my frontend?" | Check config files | portctl group (organized by role) |
Commands
| Command | What it does |
|---|---|
portctl scan |
List all listening ports with process info, service type, memory, uptime |
portctl <port> |
Inspect a single port (shorthand for portctl info <port>) |
portctl fix <port> |
Identify, classify, safely terminate, suggest restart |
portctl fix <port> --run "cmd" |
Fix and auto-restart your dev server |
portctl kill <port> |
Direct kill with safety checks and confirmation |
portctl group |
Ports organized by role: frontend, backend, database, infra |
portctl doctor |
Auto-diagnose stale servers, idle processes, port conflicts |
portctl doctor -y |
Auto-fix all safe issues |
portctl history |
View past actions with timestamps and outcomes |
portctl history --stats |
Success rate, most killed port, most killed process |
portctl project |
Detect project type and suggest dev commands |
portctl ui |
Interactive TUI with arrow-key navigation |
All commands support --json for scripting and CI integration.
Developer Workflows
Add to your package.json
Now npm run dev always works, even if port 3000 is occupied from a previous crash.
Shell alias for instant recovery
# ~/.zshrc or ~/.bashrc
Pre-commit / CI check
# Ensure no stale dev servers before running tests
| &&
Debug stuck servers
# What's actually holding port 8080?
# See all dev ports organized by role
# Nuclear option: fix everything
How It Works
portctl is not kill -9 with extra steps. It's a classification engine that understands your dev environment:
- Scan - queries the OS for all listening ports and resolves PIDs via sysinfo (no shell hacking)
- Classify - identifies the service: Next.js, Vite, Django, Docker, PostgreSQL, Redis, and 13+ categories
- Assess - runs safety checks: blocks system-critical processes, warns about databases, approves dev servers
- Strategy - selects the right approach: Graceful (SIGTERM + wait), Escalating (SIGTERM then SIGKILL), or Force
- Execute - sends signals, waits for exit, verifies the port is free, logs the action
- Recover - detects the project type, suggests the restart command, or auto-restarts with
--run
Safety system
portctl will never blindly kill a process:
- BLOCKED: PID 0/1, launchd, systemd, sshd, kernel_task (30+ system-critical processes)
- WARNING: PostgreSQL, MySQL, Redis (data loss risk), Docker, Nginx (cascading effects)
- SAFE: Next.js, Vite, Create React App, Django dev server, Flask, Node.js, Python scripts
Architecture
src/
models/ PortInfo, ProcessInfo, DevService, ServiceKind
platform/ macOS (lsof + libc) / Linux (/proc/net/tcp + libc) / Windows (netstat + taskkill)
scanner/ Batch port scanning with sysinfo process resolution
classifier/ 13+ service classifiers with confidence scoring
engine/ Fix engine: safety checks, strategy selection, SIGTERM/SIGKILL with retry
project/ Filesystem project detection (package.json, Cargo.toml, pyproject.toml)
docker/ Container awareness via docker ps
grouping/ Port role classification (frontend/backend/database/infra)
doctor/ Auto-diagnosis: stale servers, idle processes, crowded ports
history/ Action log persisted to ~/.portctl/history.json
plugin/ Extensible ServiceDetector trait for custom detectors
cli/ Clap v4 commands + colored output + ratatui interactive TUI
Built in Rust. ~980KB binary. Zero runtime dependencies.
Comparison
| kill-port | fkill | portctl | |
|---|---|---|---|
| Identify what's running | No | Name only | Full info (service, CWD, memory, uptime) |
| Safety assessment | No | No | Yes (safe / warn / block) |
| Graceful shutdown | No | No | Yes (SIGTERM first, escalate if needed) |
| Restart hints | No | No | Yes (project-aware) |
| Auto-restart | No | No | Yes (--run) |
| Docker awareness | No | No | Yes |
| Auto-diagnosis | No | No | Yes (doctor) |
| Port grouping | No | No | Yes (by role) |
| Action history | No | No | Yes |
| Interactive TUI | No | Yes | Yes |
| Cross-platform | Node.js | Node.js | Native binary (macOS + Linux + Windows) |
| Binary size | ~50MB (node) | ~50MB (node) | ~980KB |
Contributing
Contributions are welcome! portctl is open source and built by developers, for developers.
Ways to contribute:
- Report bugs or request features via GitHub Issues
- Add new service classifiers (Next.js, Vite, Django, and more)
- Improve platform support (macOS, Linux, Windows)
- Add new doctor diagnostics or fix strategies
- Write or improve documentation
Please open an issue before starting major work so we can discuss the approach.
See CONTRIBUTING.md for detailed guidelines.
License
MIT -- free for personal and commercial use.