---
title: "bun prune"
description: "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`.

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

```bash terminal icon="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:

```dockerfile
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:

```bash terminal icon="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`](/pm/filter)). Bun also cleans shared locations: the root `node_modules`, or `node_modules/.bun` with the isolated linker. In those locations, Bun keeps anything an unselected workspace still needs.

```bash terminal icon="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`.
- Matches packages by name. If a package is at the wrong version, Bun leaves it for `bun install` to replace. Bun only removes a nested copy (`node_modules/a/node_modules/b`) 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`.
- Removes packages disabled for the current `os`/`cpu`. 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 command still removes the rest and exits `1`.
- `--global` is not supported.
- To clean the global cache instead, use [`bun pm cache rm`](/pm/cli/pm#cache).
