npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vivero/poda

v0.1.0

Published

Prune stale node_modules directories to reclaim disk space

Downloads

61

Readme

@vivero/poda

Prune stale node_modules directories to reclaim disk space. Built for developers who maintain many Node.js/TypeScript projects.

Poda — Spanish for "pruning."

Quick Start

pnpm install -g @vivero/poda

poda ~/Projects

That's it. Poda scans your projects, shows what's reclaimable, and lets you browse and select what to prune.

What It Does

$ poda ~/Projects

Scanned 47 projects (31.5 GB in node_modules)

  🔴 Stale    12.0 GB    32 projects (reclaimable)
  🟡 Aging     6.7 GB    18 projects
  🟢 Active   12.9 GB    47 projects

── Top reclaimable ─────────────────────────────────────
  1.0 GB   old-api-server                 1 year ago
  848 MB   react-prototype                3 months ago
  690 MB   design-system (3 pkgs)         6 months ago
  668 MB   iot-dashboard                  11 months ago
  ...

? What would you like to do?
> Browse & select projects to clean
  Clean all stale projects (12.0 GB)
  Show full report
  Exit

Browse & select opens an interactive full-screen TUI:

 poda — 47 projects, 31.5 GB total

  🔴 Stale 12.0 GB (32)  🟡 Aging 6.7 GB (18)  🟢 Active 12.9 GB (47)

  [x] 🔴  1.0 GB   old-api-server                 1 year ago
  [x] 🔴  848 MB   react-prototype                3 months ago
  [ ] 🔴  690 MB   design-system (3 pkgs)          6 months ago
> [ ] 🟡  245 MB   my-saas-app                    2 months ago
  [ ] 🟢  198 MB   current-project                2 days ago

  ─────────────────────────────────────────────────────
  Selected: 2 projects — 1.8 GB    ↑↓ navigate  ␣ toggle  a stale  Enter confirm  q quit
  • Arrow keys — navigate
  • Space — toggle selection
  • a — toggle all stale projects
  • Enter — confirm and proceed to deletion
  • q / Esc — abort

Features

  • Monorepo-aware: Detects pnpm-workspace.yaml and package.json workspaces, groups workspace packages under their monorepo root instead of listing each one separately
  • Smart staleness detection: Checks git commit history, package.json mtime, and source file mtimes — takes the most recent signal
  • Build directory filtering: Skips .next, dist, build, .turbo, .cache, .git, .nuxt, .output — no false positives from build artifacts
  • Minimum size threshold: Hides entries under 1 MB by default (configurable)
  • Safe by default: Always confirms before deleting, shows exactly what will be removed
  • Dry-run support: poda clean --dry-run to preview without deleting

Commands

poda [path] (default)

The main workflow. Scans, summarizes, and presents an action menu.

poda                    # Scan from cwd or config defaultPath
poda ~/Projects         # Scan from specified path
poda --top 20           # Show top 20 reclaimable in summary

poda scan [path]

Full detailed report — every project in a table.

poda scan ~/Projects                # Full table, sorted by size
poda scan --sort age                # Sort by staleness (oldest first)
poda scan --sort name               # Sort alphabetically
poda scan --stale-only              # Only show stale projects
poda scan --top 10                  # Limit to top 10
poda scan --min-size 50             # Only show projects >= 50 MB

poda clean [path]

Batch cleaning with flags for automation.

poda clean --stale                  # Delete all stale node_modules
poda clean --older-than 6m          # Delete anything inactive > 6 months
poda clean --older-than 30d         # Inactive > 30 days
poda clean --all --dry-run          # Preview deleting everything
poda clean --stale --no-confirm     # Skip confirmation (use with care)

Duration formats: d (days), w (weeks), m (months), y (years).

poda config

View and edit configuration stored at ~/.poda/config.json.

poda config                              # Show current config
poda config set defaultPath ~/Projects   # Set default scan path
poda config set staleThresholdDays 90    # Change stale threshold
poda config set minSizeMB 10            # Only show projects >= 10 MB
poda config add excludePaths ~/Projects/my-monorepo
poda config remove excludePaths ~/Projects/my-monorepo
poda config reset                        # Reset to defaults

Configuration

Stored at ~/.poda/config.json. Created automatically on first run.

| Field | Default | Description | |-------|---------|-------------| | defaultPath | "." | Default scan path when no argument given. Supports ~. | | excludePaths | [] | Paths to skip during scanning (prefix matching). | | staleThresholdDays | 60 | Days of inactivity before a project is "stale" (🔴). | | agingThresholdDays | 14 | Days of inactivity before a project is "aging" (🟡). | | minSizeMB | 1 | Minimum size in MB to show in results. |

Staleness Detection

Poda checks multiple signals per project and uses the most recent:

  1. Git last commitgit log -1 --format=%ci
  2. package.json mtime — filesystem modification time
  3. Source directory mtime — checks src/, lib/, app/
  4. Most recent source file — newest .ts, .js, .tsx, .jsx in source dirs

Classification:

  • Active (🟢) — within agingThresholdDays (default 14)
  • Aging (🟡) — between aging and stale thresholds
  • Stale (🔴) — beyond staleThresholdDays (default 60)

Architecture

src/
├── cli.ts           # Commander setup, default + scan/clean/config commands
├── scanner.ts       # Recursive directory walker, finds node_modules
├── analyzer.ts      # Size (du -sk), staleness heuristic, concurrency-limited
├── grouper.ts       # Monorepo detection, groups workspace packages
├── interactive.ts   # Full-screen TUI with scrollable selection list
├── display.ts       # Table formatting, compact report, summaries
├── cleaner.ts       # Deletion with progress, dry-run, error handling
├── config.ts        # ~/.poda/config.json management
├── utils.ts         # Pure utility functions (duration parsing, path helpers)
└── types.ts         # Shared TypeScript interfaces

Installation

From Source

git clone <repo>
cd poda
pnpm install
pnpm run build
pnpm link --global

Development

pnpm run build       # Compile TypeScript via tsup
pnpm run test        # Run test suite (167 tests)
pnpm run lint        # Type check with tsc --noEmit

Dependencies

Runtime (4):

  • commander — CLI argument parsing
  • inquirer — Confirmation prompts and action menu
  • chalk — Terminal colors
  • ora — Spinner during scanning/analysis

Dev (4): typescript, @types/node, tsup, vitest

The interactive TUI uses zero additional dependencies — built with raw ANSI escape codes and Node's readline.

Platform Support

  • macOS — Primary target
  • Linux — Supported
  • Windows — Best-effort (not actively tested)

Design Decisions

Architectural decisions are documented as ADRs in docs/decisions/. Key decisions:

  • No nested scanning (ADR-005) — The scanner does not descend into node_modules. Nested modules are deleted with their parent.
  • Monorepo grouping (ADR-002) — Workspace packages are grouped, not listed individually.
  • Summary-first display (ADR-004) — Overview first, detail on demand.
  • Default command is the ritual (ADR-001) — poda alone = scan → summary → act.
  • Interactive TUI over checkbox prompt (ADR-008) — Full-screen browsable list with live totals.
  • Raw ANSI over frameworks (ADR-008) — No Ink/Blessed, following npkill's minimal approach.

License

MIT