bun prune

Remove packages that are not in bun.lock from node_modules

bun prune deletes everything in node_modules that the current bun.lock would not install — packages left behind after switching branches, removing a dependency, or installing with another package manager. With the isolated linker, this includes stale entries in node_modules/.bun.

It never contacts the registry, never runs lifecycle scripts, and never modifies bun.lock or package.json.

terminal
bun prune
bun prune v1.4.0 (abc12345)

- @types/node@20.11.5
- left-pad@1.3.0
2 packages removed (checked 948) [22.00ms]

Packages removed from a workspace or nested node_modules folder show the folder in parentheses, e.g. - typescript@5.4.0 (packages/app/node_modules).

--production#

Also remove everything bun install --production would not install (i.e. devDependencies). This lets you build with dev dependencies and ship without them:

COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun run build
RUN bun prune --production

--omit=dev, --omit=optional, and --omit=peer work the same way they do for bun install.

--dry-run#

List what would be removed without deleting anything:

terminal
bun prune --production --dry-run
bun prune v1.4.0 (abc12345)

- typescript@5.4.0
1 package can be removed (checked 948) [9.00ms]
  bun prune --production

--filter#

Prune only the selected workspaces' node_modules folders (same patterns as bun install --filter). Shared locations — the root node_modules, or node_modules/.bun with the isolated linker — are cleaned too, but anything an unselected workspace still needs is kept.

terminal
bun prune --production --filter app

Notes#

  • Always runs from the workspace root and covers every workspace's node_modules, even when invoked inside a workspace package.
  • Requires bun.lock to match package.json. If you edited dependencies since the last install, run bun install first.
  • Uses the same linker as bun install would. If node_modules was created with the other linker, bun prune refuses to run — pass the matching --linker, or run bun install.
  • Packages are matched by name. A package at the wrong version is left for bun install to replace. A nested copy (node_modules/a/node_modules/b) is only removed once the correct version is installed above it; otherwise Bun keeps it and prints a warning.
  • Never removes workspace folders, .bin entries still in use, dot-directories like .cache, plain files, or anything outside node_modules.
  • Packages disabled for the current os/cpu are removed. Pass --os/--cpu to prune for another platform.
  • Works on a pruned monorepo checkout (e.g. turbo prune output) the same way bun install --frozen-lockfile does.
  • If any entry fails to delete, the rest are still removed and the command exits 1.
  • --global is not supported.
  • To clean the global cache instead, use bun pm cache rm.