Find and safely clean up disk space hogs in your projects — caches, build outputs, logs, and junk files.
declutter scans a directory, tells you exactly what's wasting space, and helps you reclaim it. It is dry-run by default: nothing is ever deleted unless you explicitly pass --yes.
$ declutter ~/projects --categories
📦 ~/projects
1.2 GB total scanned · 812 MB reclaimable
cache 812.3 MB 68% (3421 items)
logs 4.2 MB 0% (187 items)
trash 0.5 MB 0% (12 items)
archives 0.0 MB 0% (0 items)
other 398.0 MB 33% (5204 items)
Dry run: 812 MB would be freed. Pass --yes to delete.
Every project folder accumulates the same junk: node_modules reinstall caches, build outputs, logs, archives, .DS_Store. Cleaning it by hand is slow, nervous, and file-by-file. declutter makes it safe and one command.
npm install -g declutterRequires Node.js 18+.
Usage: declutter [path] [options]
Options:
--dry-run Show what would be deleted (default: always on unless --yes)
--yes Actually delete the reclaimable files (cache, logs, trash)
--categories Show the top files per category, sorted by size
--exclude PATH Never delete files under this path (repeatable)
--older-than N Only delete files modified more than N days ago
--report [file] Write an HTML report (default: declutter-report.html)
--json Output machine-readable JSON
--help Show this help
--version Show version
The --older-than N flag is an extra safety gate: it only deletes files whose last-modified time is more than N days ago. Fresh cache files (recently modified, possibly still in use) are left alone. Combined with --exclude, you get two independent protections before anything is deleted.
The age gate is reflected everywhere you look: the dry-run total, the --json output (reclaimableAfterAgeGate / tooNewBytes), and the HTML report all show how much is actually freed once files modified within the last N days are set aside — so the preview always matches what --yes will delete.
Customize the categories with a .declutterrc.json in the target directory (or in your home directory as a fallback):
{
"cache": ["node_modules", "vendor", ".cache"],
"logs": ["*.log", "*.tmp"]
}Any category you don't specify keeps its defaults. Patterns support *.ext suffix matches, exact names, and ~$ prefix matches for Office temp files.
declutter ~/projects --report writes a self-contained declutter-report.html (no external assets) showing the scan summary and the top files per category — handy for sharing or reviewing before a cleanup.
- Dry-run by default.
declutternever deletes unless you pass--yes. - Files only. Directories are never deleted, ever. The delete path verifies every target is a regular file before unlinking.
- Only reclaimable categories. Caches, logs, and trash are eligible. Your source files, configs, and anything uncategorized are untouched.
- Graceful on missing files. Files that vanish mid-scan are skipped, not fatal.
| Category | Matches |
|---|---|
cache |
node_modules, .cache, .npm, .pnpm-store, .yarn, dist, build, coverage, .next, .turbo |
logs |
*.log, *.tmp, *.bak, npm-debug.log*, yarn-error.log* |
archives |
*.zip, *.tar, *.gz, *.tgz, *.7z, *.rar, *.dmg, *.pkg |
trash |
.DS_Store, Thumbs.db, desktop.ini, ~$* |
Files that don't match any category land in other and are never deleted.
For scripting and CI pipelines:
declutter ~/projects --json{
"target": "C:\\Users\\me\\projects",
"totalBytes": 1288490188,
"config": null,
"olderThanDays": 14,
"reclaimableBytes": 851443712,
"reclaimableAfterAgeGate": 274877907,
"tooNewBytes": 576565805,
"categories": {
"cache": { "bytes": 851443712, "count": 3421 },
"logs": { "bytes": 4404019, "count": 187 }
}
}When --older-than is set, reclaimableAfterAgeGate and tooNewBytes tell a CI script exactly what a --yes run would actually free (files modified within the last N days are set aside). Without the flag, reclaimableAfterAgeGate equals reclaimableBytes.
npm test # run the test suite (node:test, zero test deps)
npm link # install locally for testingMIT © Faizan