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

bun-manage-workspace

v0.4.2

Published

Bun Multi-Workspace CLI: catalog updater, graph-aware script runner with cache, graph diagnostics

Readme

bun-manage-workspace

A friendly CLI for managing bun workspaces — it fills the gaps in bun's native workspace support. Zero runtime dependencies, bun-only.

Install it as bun-manage-workspace, call it as bmw.

What it does

  • bmw run — run a script across your workspace, in dependency order, with caching. Need to build every workspace dependency of the app you're working on before building the app itself? That's the one-liner bun doesn't have.
  • bmw update — interactively update your catalogs (catalog / catalogs in the root package.json), which bun update --interactive doesn't touch.
  • Plus small helpers: bmw graph, bmw why, and bmw cache.

Getting started

bun install -g bun-manage-workspace

Or skip the install and run it directly:

bunx bmw <command>

You need bun, and a repository whose root package.json declares workspaces. Then, from anywhere in the workspace:

bmw run build        # build the current package's deps, then the package
bmw run test --all   # run "test" everywhere
bmw update           # pick which catalog entries to bump

That's the 80% use case. The rest of this README is the fine print.

bmw run <script> [flags]

Runs a package.json script across the workspace dependency graph.

By default, everything starts at once, but each package waits for its workspace dependencies to finish first — a package's script spawns the moment all of its in-plan dependencies have completed, with no global wave barriers. If a package fails, everything that (transitively) depends on it is skipped and the run aborts with that exit code.

What gets run?

| Mode | What runs | | --- | --- | | default (inside a package) | all transitive workspace dependencies of the cwd package, then the package itself | | default (at the workspace root) | all non-private packages | | --to, -t <pkg> | the package and its workspace dependencies (from any cwd, repeatable) | | --from, -f <pkg> | the package and its dependents (from any cwd, repeatable) | | --only, -o <pkg> | just the package, no dependencies (repeatable) | | --deps, -d [pkg] | only the package's dependencies, without the package itself (default: cwd package) | | --dependents, -D | default plan plus the packages that (transitively) depend on cwd, after it | | --all, -a | all non-private packages, regardless of cwd | | --no-deps | only the cwd package | | --parallel, -p | run everything at once, without waiting for dependencies | | --no-cache, -C | skip cache reads (entries are still refreshed) | | --dry-run, -n | print the plan without executing (shows cache hits) | | --watch, -w | re-run the plan whenever a package in it changes |

Selectors accept a package name or a path (relative to cwd or absolute): bmw run build --to packages/api works the same as --to @acme/api. Values also work attached (-t@acme/api, -t=@acme/api), and boolean short flags cluster (-an = --all --dry-run).

Repeated selectors union: bmw run build --to @acme/api --to @acme/web builds both apps and everything they need.

Packages without the script are skipped with a note. In the default cwd-relative mode, the script must exist in the cwd package.

bmw run build                  # build deps, then the current package
bmw run build --dependents     # ...and everything that depends on it
bmw run test --all             # run "test" across the whole workspace
bmw run build --dry-run        # show the plan without executing

Watch mode

bmw run build --watch runs the plan once, then watches every package in it. On any change (respecting the same ignore rules as the cache: node_modules, dist, .bmwignore, …) it re-runs the plan — and thanks to the cache, only the changed packages and their dependents actually rebuild. Changes arriving mid-run are coalesced into a single follow-up run. Uses native file watching, with a polling fallback on platforms without recursive watches.

Caching

Results are cached in <root>/node_modules/.cache/bmw/run/. The cache key combines the script name, a hash of the package's files, the workspace-root manifest and lockfile (package.json, bun.lock/bun.lockb, bunfig.toml — so a dependency bump followed by bun install invalidates everything), and the content keys of its workspace dependencies — so changing a dependency automatically invalidates its dependents. Cache hits are skipped:

▸ @acme/core — unchanged (cache), skipped

Hashed files exclude node_modules, .git, .turbo anywhere in the tree, plus the output directories dist, build, out, .next and coverage at the package root. Want more ignores? Add globs (one per line, # comments allowed) to a .bmwignore file in the workspace root and/or in a package directory. Override the cache location with the BMW_CACHE_DIR environment variable.

bmw update [flags]

An interactive updater for catalog dependencies — like bun update --interactive, but for catalog / catalogs in the root package.json.

Use the arrow keys to move, space to select (nothing is selected by default), a to toggle all, enter to confirm, esc to cancel. Entries are grouped with aligned columns and colored by bump kind (major red, minor cyan, patch green, prerelease yellow).

The bump level is switched live in the picker: p shows only patch bumps (same major.minor), m stays within the current major (the default), l offers the latest version including major jumps. Selections are preserved when switching levels.

| Flag | Effect | | --- | --- | | default | bump within the current major, interactive picker (p/m/l switch the level) | | --level <lvl> | bump level for non-interactive runs: patch, minor or latest (default minor) | | --all | non-interactive, update everything (automatic outside a TTY) | | --registry <url> | override the default npm registry |

Custom registries (e.g. Verdaccio) are handled by bun itself — metadata is fetched via bun info, so the same bunfig.toml / .npmrc configuration that bun install uses (scoped registries, auth tokens) applies here too.

Only the root package.json is modified, and its formatting (indentation, trailing newline, key order) is preserved. Run bun install afterwards to update the lockfile.

bmw cache [clean]

Shows the cache location, entry count, and size. bmw cache clean removes all cached run results — the next bmw run rebuilds everything from scratch. Respects BMW_CACHE_DIR.

bmw graph [--all]

Prints the workspace dependency tree from the cwd package — or every tree in the workspace with --all. Cycles and already-shown packages are marked.

bmw why <package>

Shows the reverse dependency chains leading to <package> — who depends on it, and through what.

bmw why @acme/core
# Packages depending on "@acme/core":
#   @acme/app → @acme/utils → @acme/core
#   @acme/web → @acme/core

Workspace linking rules

A dependency on another workspace package links (joins the graph) when its specifier is workspace:* / workspace:^ / workspace:~ / workspace:<range>, or a plain semver range satisfied by the local version. catalog: references and unsatisfied ranges are treated as external (registry) dependencies. A workspace: specifier that doesn't match the local version is a configuration error and aborts with a clear message.

Development

git clone <repo> && cd bun-manage-workspace
bun install
bun test            # unit + integration tests (fixture monorepo)
bun x tsc --noEmit  # typecheck
bun run src/cli.ts --help

Publishing

Publishing is handled by GitHub Actions via npm.

License

MIT