Hakai: How I Shaved 14 Seconds Off Deleting Folders and Why That Mattered
march 1, 2026
Because waiting 15 seconds for npkill to tell me how much space my old Next.js projects are taking is 14 seconds too long.
Dev Story · Projects · Rust · Bun · CLI · Performance
Hakai: How I Shaved 14 Seconds Off Deleting Folders and Why That Mattered
Let me introduce you to the logical conclusion of my war on
node_modules.
If you read my previous post about wimo purge, you might be thinking: "Wow, you really hate node_modules, don't you?"
Yes. But honestly, my hatred wasn't fully optimized yet.
npkill has been the standard for finding and destroying heavy artifact folders. And it works fine! If you scan a small directory. But drop npkill into a ~/projects folder containing 50,000 deep directories spanning 5 years of side projects?
You wait.
You watch it sequentially crawl the directories. You watch the size calculations happen sequentially. You select a 5GB folder to delete, and the entire UI locks up while Node.js tries desperately to delete via thousands of blocking I/O calls.
This is unacceptable. This is a waste of human potential.
Enter hakai (破壊).
Over-Engineering Directory Deletion
"Hakai" means "destruction" in Japanese. I needed something that lived up to the name.
The problem with fast file operations is that JavaScript isn't meant for it. So I reached for the ultimate meme language of our generation: Rust.
Rust is fast. Blazingly fast, as they say. I used the rayon crate for parallel scanning, effectively utilizing every CPU core I had to blast through directory trees simultaneously.
But I didn't want a static, boring CLI output. I wanted the rich, interactive TUI experience. And building complex TUIs in Rust can get messy quickly.
So I made a choice that will likely infuriate purists.
The Forbidden Alliance: Rust + Bun
The filesystem engine—the core that does the scanning, size calculation, async deletion (via tokio), and risk analysis—is written in compiled Rust.
The interface—the part that looks pretty, handles keybinds, diff-based rendering, and regex search—is written in Bun.
Why Bun? Because it starts up in under 50ms, is natively fast, and I already knew how to build TUIs in TS.
To connect them, I built a brutal, efficient newline-delimited JSON Inter-Process Communication (IPC) protocol.
The Rust engine scans 8,000 directories a second and fires a relentless barrage of JSON down stdout.
The Bun frontend catches the stream on stdin, parses it effortlessly, and renders the TUI at 60fps.
It is a beautiful, chaotic marriage.
The Benchmarks of Spite
Here are the results of this completely unhinged architecture:
| Operation | npkill (Node) | hakai (Rust+Bun) | Gain |
|---|---|---|---|
| Scan 50k dirs | ~8–12s | <1s | 10–15× |
| Size calculation | Sequential | Parallel | 8–12× |
| Delete 5GB folder | ~45s (blocks) | Async (smooth) | 4–6× |
When you tell hakai to delete 100 folders at once via multi-select, it deletes up to 8 of them concurrently via async tokio tasks. It finishes before you can even move your hand back to your mouse.
Was it worth it?
I spent an entire weekend configuring Rust cross-compilation targets, fighting token limits across IPC pipes, and ensuring Windows Git Bash TTY issues were resolved, all to save roughly 10 seconds of my day once a month.
So, yes. Obviously.
If you also wish to obliterate gigabytes of data with terrifying speed, grab hakai on GitHub. Use with caution.