Port Kill clears the port, then manages the process behind it
Port Kill helps you find and free ports and caches blocking your dev work.
At a glance
- What is it?
- treadiehq's Port Kill is a Rust binary that frees busy local ports, manages development caches, and starts services from .port-kill.yaml, with a macOS status bar app layered on top. It fits a solo developer fighting stuck servers, and it stops well short of anything you would want running on a shared host.
- Who is it for?
- This is a workable default for a solo developer on macOS who keeps losing ports to a crashed server, and the YAML orchestration earns its place once a project runs more than two services. It is the wrong choice for shared or production hosts, where whatever holds a port is not yours to kill, and for anyone who needs a pinned, signed binary rather than a shell pipe.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two binaries with a parity claim the manifest narrows
Port Kill ships two Rust binaries out of one crate. `port-kill` is a status bar app on macOS plus a full CLI, `port-kill-console` is the pure CLI build for every platform, and Cargo.toml points them at src/main.rs and src/main_console.rs respectively.
The README calls this full feature parity and states that both binaries support smart restart, service detection and orchestration, which reads stronger than the manifest supports. The tray crates, tray-icon 0.10 and winit 0.29, sit behind a macOS only target block, and the features table declares default = [] with embed_icon as the single opt in. So the difference between the two builds is the window, not the command set. The crate targets edition 2021 and ships one shared library, src/lib.rs, which is why the console binary inherits the same flags.
Positional ports map straight to a clearPort call
The CLI takes port numbers as positional arguments, and the quick reference notes that positional ports imply clearPort on each one. Several can go into a single call:
# Kill whatever is blocking a port
port-kill 3000
# Kill multiple ports
port-kill 3000 5000
# List ports in use (one-time snapshot)
port-kill --list
# Confirm before killing
port-kill 3000 --safeThe listing is a one time snapshot rather than a watch. `--safe` is the only confirmation gate on the plain command, and nothing documented scopes a kill to a process you started, so an off by one port number goes after whatever holds it. Argument parsing runs through clap 4.0 and process enumeration through sysinfo 0.30, both listed in the dependency block shared by the two binaries.
One detail a fast read misses: the CLI quick reference in the README stops mid expression and its fenced block never closes, so the option list is cut off before the optional arguments are named. Everything documented about this command line comes from the quick start block.
Installing pipes a remote script into your shell
Installation is a single pipe from the project homepage, with a separate Windows path that fetches a batch file instead:
# macOS/Linux
curl -fsSL portkill.com/install | bash
# Windows (PowerShell or CMD)
curl -fsSL portkill.com/install-windows -o install-release.bat && install-release.batNeither line pins a version or prints a checksum, so the site decides what lands on your machine at the moment you run it.
Windows carries one extra rule, written in capitals in the README: after installing you must restart your terminal completely for PATH changes to take effect, and the failure surfaces as `'port-kill' is not recognized`. The documented path out is a diagnostics script plus a direct call to the executable:
powershell -Command "Invoke-WebRequest -UseBasicParsing -Uri 'https://raw.githubusercontent.com/treadiehq/port-kill/main/diagnose-installation.bat' -OutFile 'diagnose.bat'"; .\diagnose.bat
"%USERPROFILE%\AppData\Local\port-kill\port-kill.exe" --listThat second line is the useful one, since it works with no PATH at all and tells you whether the install failed or your shell has simply not picked up the change yet. The tree also carries install.sh, manual-download.bat and verify-installation.bat, none of which the install section mentions.
Smart restart runs a command saved by an earlier kill
Restart is not self contained. The README pairs a plain kill with a restart flag and says the kill step saves restart info automatically:
# Kill and restart a process (saves restart info automatically)
port-kill 3000 # Kill process on port 3000
port-kill --restart 3000 # Restart it with saved command
# View restart history
port-kill --show-restart-history # See all restartable ports
# Clear restart info
port-kill --clear-restart 3000 # Remove saved restart infoSo `--restart 3000` has nothing to act on until a previous kill recorded the startup command, and `--show-restart-history` is the only view onto which ports are restartable. `--clear-restart 3000` discards the record, which matters if the saved command points at a script you have since rewritten.
The heading labels this block NEW!, which is a claim written in the text rather than a version number you can check against anything.
Guard mode reserves a port and restarts it unattended
Guard mode turns the cleaner into a supervisor. `--guard 3000 --guard-auto-restart` watches the port and restarts the process when it dies, and the second form in the README combines that with reservations, which bind a port to a named project and a named process:
# Guard a port and auto-restart if process dies
port-kill --guard 3000 --guard-auto-restart
# Works with reservations
port-kill --guard-mode --guard-auto-restart \
--reserve-port 3000 \
--project-name "my-app" \
--process-name "npm"Read the second form carefully and the targeting is narrow by design: the port, the project directory and the process name are all supplied, so the guard acts on what it was told about rather than on whatever appears on 3000 later.
This is the closest the CLI comes to a whitelist. The whitelist behaviour lives in separate scripts under examples/, named port-guard-whitelist.js and port-guard-simple.js, which are JavaScript files rather than flags of the Rust binary. Nothing in the README says what happens when two guards claim the same port, and the YAML configuration has no key for guarding at all.
Orchestration runs .port-kill.yaml in depends_on order
`--init-config` writes .port-kill.yaml into the project root, after which the service commands read it:
# Initialize configuration
port-kill --init-config
# Start all services (respects dependencies)
port-kill --up
# Stop all running services
port-kill --down
# Restart a specific service
port-kill --restart-service backend
# Check status of all services
port-kill --statusThe file itself is a small schema. A service needs command, and can add port, dir, env, depends_on, startup_delay and healthcheck. A global version key and a global env block sit beside the required services map:
version: "1"
# Global environment variables
env:
NODE_ENV: development
DEBUG: "true"
services:
# Frontend service
frontend:
command: npm run dev
port: 3000
dir: ./frontend
startup_delay: 2The dependency example makes ordering explicit, starting database, then redis, then api:
services:
api:
command: npm start
depends_on:
- database
- redis
database:
command: docker-compose up database
redis:
command: redis-serverTwo gaps are worth naming. healthcheck is listed as an optional field, yet no example sets it and no documented flag invokes it. `--down` stops every running service as a unit, with `--restart-service backend` the only per service verb, so there is no documented way to take one service out of the running set without restarting it. In the longer example the database service carries port 5432 and startup_delay 5 while the frontend uses startup_delay 2 and a dir, and the database service has no port at all, which is the clearest proof that port is optional. A second file is reachable through `--config-file my-config.yaml --up`.
Two different safety flags guard killing and cache deletion
Cache management is the destructive half of the tool, and it uses its own vocabulary:
# Cache management
port-kill cache --list
port-kill cache --clean --safe-delete
port-kill cache --doctorNotice the naming split. Confirmation before a kill is `--safe`, confirmation before a cache clean is `--safe-delete`, and both are opt in rather than the default. `--doctor` is the only diagnostic named anywhere for the cache side, the counterpart to the Windows installation script, and directory walking is handled by walkdir 2.
The examples directory holds nine files, from cache-management.js and file-cleanup.js through port-guard-multi.js and port-guard-whitelist.js. They are JavaScript, in a Rust project, so treat them as usage sketches rather than code the binary loads. Which project types get detected for auto start is spelled out though: npm, yarn and pnpm scripts from package.json, services from docker-compose.yml, Procfile entries, and Python entry files such as app.py and manage.py, after which `--detect` lists them and `--start npm:dev` launches one.
Custom terms in the manifest, and an update check that reaches out
Two things need checking before this goes into your setup.
The licence field on GitHub reads Other, while Cargo.toml declares license = "FSL-1.1-MIT" and a LICENSE file sits at the repository root, so the terms you inherit live in a custom text rather than in a name GitHub recognises. The last push was on 2026-04-03, and the tag line runs from v0.5.41 back through v0.5.40 and v0.5.39 across March, a fast string of patch numbers with no minor release where a behaviour change would be easier to spot.
Updates are a network operation inside the CLI: `--check-updates` and `--self-update` appear in the quick start, and the manifest carries reqwest 0.11 with blocking and json features to make the call. Nothing in the README describes an offline mode, a pinned version flag, or a checksum for the binary it fetches.
The source tree is wider than the documented surface. Directories named mcp/, dashboard/, ci-samples/ and .cursor/ sit at the top level alongside run-dashboard.sh and run-dashboard.bat wrappers, and no flag in the quick start opens either of the first two. Build scripts come in one file per platform (build-macos.sh, build-linux.sh, build-windows.bat), with flake.nix, shell.nix, test-nix.sh and validate-nix.sh beside them, so a source build route exists even though the install section only offers the curl pipe.
Editorial conclusion
This is a workable default for a solo developer on macOS who keeps losing ports to a crashed server, and the YAML orchestration earns its place once a project runs more than two services. It is the wrong choice for shared or production hosts, where whatever holds a port is not yours to kill, and for anyone who needs a pinned, signed binary rather than a shell pipe. Before trusting it, check that the guard flags behave on a port you can afford to lose, and that .port-kill.yaml matches what your project already starts.
Frequently asked questions
Does port-kill work on Linux and Windows, or is it macOS only?
Both. The port-kill binary adds a macOS status bar app, while port-kill-console is the pure CLI build for all platforms, and the project states that both carry the same features including smart restart, service detection and orchestration. On Windows you must restart your terminal after installing so PATH changes take effect.
How do I install Port Kill on macOS or Linux?
Run curl -fsSL portkill.com/install | bash. The command pipes a script straight into your shell and pins no version, so what you get depends on what the site serves at that moment.
Will Port Kill kill a process I did not start?
Positional ports imply a clearPort on each one, so whatever holds the port is the target, with no documented filter for processes you launched. Confirmation exists as port-kill 3000 --safe, and whitelist behaviour appears only in separate example scripts such as examples/port-guard-whitelist.js.
Can Port Kill start my project's services for me?
Yes. --detect discovers npm, yarn and pnpm scripts, docker-compose.yml services, Procfile entries and Python files such as app.py, and --start npm:dev launches one of them. For several services, --init-config writes .port-kill.yaml and --up starts them in depends_on order, with --status and --down for the rest.
Does port-kill self-update, and can I pin a version?
The quick start lists --check-updates and --self-update, and the manifest pulls in reqwest 0.11 with blocking and json features for those calls. No flag for pinning a version, no checksum for the downloaded binary and no offline mode appear in the documentation.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/treadiehq-port-kill)Was this useful?