tidyup
Your dev machine, minus the mess.
Kill whatever is squatting on port 3000. Delete the 40 GB of node_modules and target folders from projects you forgot about. Start your whole dev stack with one command.
Why
Every developer has seen these:
Error: listen EADDRINUSE: address already in use :::3000
Your disk is almost full.
The first one sends you to Stack Overflow for the lsof -ti :3000 | xargs kill incantation, again. The second one is 30 old projects, each with a gigabyte of node_modules, a few Rust target folders at 5 GB each, and a .venv from that weekend you tried machine learning.
tidyup handles both: one small binary, no runtime, no config needed.
Install
Works on macOS and Linux. It uses lsof and ps, which both ship with.
Ports: what's running, and stop it
- Shows the project folder each process runs from, so you can tell your three
nodeprocesses apart. - Hides system noise. AirPlay, Spotify and other processes running from
/stay out of the list unless you pass--all. - Stops nicely first. SIGTERM, a 3 second wait, then SIGKILL only if the process is still around. That's what happened to the stubborn Python server above.
Clean: get your disk back
It only deletes what your tools can rebuild, and only when the project file that creates it sits next to it. A node_modules without a package.json beside it is left alone. So is a build/ folder you made yourself.
| Deletes | When next to | |
|---|---|---|
node_modules .next .nuxt .svelte-kit .turbo .parcel-cache .angular |
package.json |
JavaScript |
target |
Cargo.toml · pom.xml |
Rust · Maven |
build .gradle |
build.gradle(.kts) · settings.gradle(.kts) |
Gradle |
.venv venv |
pyproject.toml · requirements.txt · setup.py · Pipfile |
Python |
Pods |
Podfile |
CocoaPods |
.dart_tool build |
pubspec.yaml |
Dart · Flutter |
vendor |
composer.json |
PHP |
_build deps |
mix.exs |
Elixir |
.zig-cache zig-out |
build.zig |
Zig |
It never looks inside hidden folders (.git, .vscode, .cargo, …), .app bundles or ~/Library, so your editor extensions keep their node_modules.
Sizes are honest. tidyup reports what deleting actually frees. A pnpm project's node_modules is mostly hard links into pnpm's shared store, so it shows up small, because deleting it frees almost nothing.
Age is the last time you touched the project, not its build folder. --older-than 30 means "projects I haven't opened in a month".
Up: your dev stack in one command
Put a tidyup.toml in your project (or run tidyup up --init):
[[]]
= "web"
= "pnpm dev"
= 3000 # whatever holds this port is stopped first
[[]]
= "api"
= "uvicorn main:app --port 8080"
= 8080
[[]]
= "worker"
= "pnpm worker"
= "packages/worker" # optional, relative to tidyup.toml
= { = "debug" }
- Frees the ports first, so a leftover dev server from yesterday doesn't stop you.
- One terminal, colored prefixes, colors from your tools kept.
- ctrl-c stops everything, including the processes your services started themselves (
pnpm→node→esbuild). No orphans holding port 3000 tomorrow.
The dashboard
Run tidyup with no arguments (or tidyup ui ~/code) for both tools in one screen. Ports refresh every 2 seconds; the Clean tab fills in while it scans.
| Ports tab | Clean tab | ||
|---|---|---|---|
x |
stop | space |
mark |
X |
force kill | a |
mark all |
a |
show/hide system processes | d |
delete marked (or current) |
r |
refresh | s / t |
sort by size / age, again to flip |
r |
rescan |
tab or 1/2 switches tabs, ↑↓ or j/k moves, q quits.
Contributing
Issues and pull requests are welcome. Before opening a PR:
&& &&
The GIFs above are recorded with VHS against made-up data. TIDYUP_DEMO=1 makes tidyup show fake ports and projects and only pretend to stop and delete them. To re-record one:
&& &&