Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🚪 vacate

Something is squatting on your port. Make it vacate.

The zero-bloat, lightning-fast Rust TUI for when you can never remember lsof syntax.

crates.io CI License: MIT Language: Rust Build: Zero Bloat


💡 Why vacate Exists

I’ve been in tech for almost two decades. I’ve configured thousands of servers, deployed countless stacks, and built system architectures from scratch.

And yet, every single time a dev server crashes while holding onto port 8080, I still have to Google lsof -i :8080.

Is it awk '{print $2}'? Do I pipe it into xargs kill -9? What if it's on Linux and I need netstat -tulpn or ss -tulpn? Life is too short to memorize obscure terminal flags for the 500th time.

So I built vacate:

  • Instant (<5ms launch time) because it’s compiled Rust, not Electron or Python.
  • 🪶 Sub-5MB binary & zero memory bloat.
  • 🎯 Single-purpose simplicity. Type a port number, see what's hogging it, kill it, move on with your day.

Yes, there are a hundred port managers on GitHub. This one is mine, it's open-source (MIT), and it never forgets the commands so I don't have to.


⚡ Quick Start

1. Direct Target Mode (Quick Kill)

When you already know which port is blocked:

# Inspect & interactively kill whatever is on port 8080
vacate 8080

# Force kill immediately without prompt
vacate 3000 --force
$ vacate 8080
PORT   PROTO PID     PROCESS USER  MEMORY
8080   TCP   39865   node    cyrus 42 M

Send SIGTERM to node (PID 39865)? [y/N] y
Sent SIGTERM to node (PID 39865).
Flag Effect
(none) Show what's there, ask, then SIGTERM
-y, --yes Skip the prompt, still SIGTERM
-f, --force Skip the prompt, send SIGKILL

Exit codes: 0 killed · 1 nothing on that port · 2 you said no · 3 found it but couldn't signal it.

2. Browse Mode (TUI)

Run it bare when you don't know which port you're looking for:

vacate
 VACATE  41 listening                                                v0.1.0
 PORT   PROTO PID      PROCESS                      USER           MEMORY
 3306   TCP   1685     mysqld                       cyrus              7.2 M
▌6379   TCP   1331     redis-server                 cyrus              1.4 M
 11434  TCP   1626     ollama                       cyrus               12 M
 18789  TCP   1328     node                         cyrus               32 M
 j/k move · / search · ⏎ SIGTERM · K SIGKILL · r refresh · q quit
Key Action
j / k, / Move
g / G, Home / End Jump to top / bottom
Ctrl-d / Ctrl-u Jump 10 rows down / up
/ Fuzzy filter by port, process, or user
Enter SIGTERM the selected process
K (Shift+K) SIGKILL the selected process
r Rescan
q, Esc, Ctrl-c Quit

While filtering, Enter keeps the filter and hands the keyboard back to the bindings above; Esc clears it. / still aim while you type.

On k: vim muscle memory wins — lowercase k moves up. Killing is Enter (graceful) and Shift-K (force), so a stray k can never kill anything.


📦 Install

cargo install vacate

Or from source:

cargo install --git https://github.com/jcyrus/vacate   # latest main
cargo install --path .                                 # from a clone
cargo build --release                                  # ./target/release/vacate

Requires Rust 1.88+. Linux and macOS.


📐 Does it actually deliver?

Release build on Apple Silicon, hyperfine -N, 700+ runs, ~45 listening sockets. Your numbers will differ, but the shape shouldn't:

Claim Measured
Launch time 2.6 ms to start; 4.9 ms including a full system-wide socket scan
Binary size 672 KB stripped (aarch64-apple-darwin)
Idle CPU in the TUI 0% — the event loop blocks on input, there is no polling tick
Runtime dependencies none beyond libc; no daemon, no config file, no network

🔍 How it works

No shelling out to lsof, ss, or netstat — parsing another tool's output is exactly the fragility this exists to avoid. Instead:

  • Sockets come from netstat2: netlink sock_diag on Linux, libproc on macOS. Either way the PID behind a socket is found by walking open file descriptors, which is why you only see processes you have the rights to inspect.
  • Process details come straight from the OS: proc_pidinfo on macOS, /proc/<pid>/status on Linux. Only the PIDs that actually hold a socket get looked up, so there's no whole-system process scan to pay for.
  • Killing is a plain kill(2), with guardrails: vacate refuses to signal PID 0, PID 1, or itself.

TCP sockets are listed only in the LISTEN state — an established connection isn't what's holding your port. UDP sockets are listed when bound.

Platform notes

Linux and macOS. Because a socket is tied back to its process through that process's open file descriptors, an unprivileged run mostly shows ports you own — other users' listeners may be missing entirely, or appear with ? for name and user. Run sudo vacate to see the rest.


📄 License

MIT — see LICENSE.

About

Something is squatting on your port. Make it vacate. Zero-bloat Rust TUI + CLI for when you can never remember lsof syntax.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages