# lpm bench (/docs/dev/bench)



```bash
lpm bench [-- args...]
```

Detects whether the project uses `vitest bench` and runs it, forwarding any trailing arguments verbatim.

## Examples [#examples]

```bash
lpm bench
lpm bench src/parser.bench.ts
lpm bench -- --reporter=verbose
```

## Detection [#detection]

If `vitest` is in `dependencies` or `devDependencies`, `lpm bench` runs `vitest bench` with whatever args you pass. Otherwise, if `package.json` has a `bench` script, `lpm bench` runs that script via the shell. The script fallback is only consulted when vitest is not declared. Use it for non-vitest benchmark frameworks (mitata, tinybench standalone, hyperfine).

## Argument forwarding [#argument-forwarding]

Anything after the command (or after `--`) is forwarded to the runner:

```bash
lpm bench -- --reporter=json --outputFile=bench.json
```

## Workspaces [#workspaces]

```bash
lpm bench --all                            # every member
lpm bench --filter web                     # exact name
lpm bench --filter '@scope/*'              # glob
lpm bench --filter-prod ...shared          # prod graph closure
lpm bench --affected --base develop
lpm bench --filter './packages/*' --workspace-concurrency 2
```

Detection runs per member. A workspace member with no installed bench runner and no `scripts.bench` becomes a per-member detection failure in the JSON envelope rather than aborting the whole run. `--all` is mutually exclusive with filters and `--affected`.

`--filter` and `--filter-prod` compose with `--affected` the same way as [`lpm test`](/docs/dev/test): the affected set is unioned with the filter result. `--filter-prod` uses the same grammar as `--filter`, but closure operators ignore `devDependencies`.

`--workspace-concurrency <N>` caps how many selected workspace members run at once within each topological level.

### Forwarding runner flags with the same names [#forwarding-runner-flags-with-the-same-names]

The workspace flags (`--all`, `--filter`, `--filter-prod`, `--affected`, `--base`, `--fail-if-no-match`, `--workspace-concurrency`) are claimed by LPM CLI. To pass any of them through to the bench runner itself, put them after `--`:

```bash
lpm bench -- --filter pattern             # forwards --filter to vitest bench
lpm bench --filter web -- --reporter=json # workspace + forwarded args
```

### Watch with a workspace selector [#watch-with-a-workspace-selector]

Same gating as `lpm test`: watch is allowed when the selection resolves to exactly one member, rejected when it resolves to two or more (would start N watchers) or zero (nothing to watch).

```bash
lpm bench --filter web --watch            # ✓ one member, one watcher
lpm bench --all --watch                   # ✗ rejected: N watchers
lpm bench --filter typo --watch           # ✗ rejected: nothing to watch
```

When the filter resolves to exactly one member, `lpm bench` runs against that member's directory as if you'd `cd`-ed in.

## Flags [#flags]

| Flag                                    | Effect                                                                                                  |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `--all`                                 | Run in every workspace member                                                                           |
| `--filter <expr>`                       | Select workspace members by the [filter grammar](/docs/packages/workspaces#filter-grammar) (repeatable) |
| `--filter-prod <expr>`                  | Select workspace members with production-only dependency closures                                       |
| `--affected`                            | Run only in members affected by changes vs `--base`                                                     |
| `--base <REF>`                          | Git base ref for `--affected` (default: `main`)                                                         |
| `--changed-files-ignore-pattern <glob>` | Ignore matching git-diff paths for `--affected` / `[git-ref]` filters                                   |
| `--test-pattern <glob>`                 | Treat matching git-diff paths as test-only for `--affected` / `[git-ref]` fan-out decisions             |
| `--fail-if-no-match`                    | Exit non-zero if no member matches the filter set                                                       |
| `--workspace-concurrency <N>`           | Limit concurrent workspace members for `--all`, `--filter`, or `--affected` runs                        |

Anything after `--` (or trailing) is forwarded to the bench runner.

Plus the [global flags](/docs/commands#global-flags).

## `--json` in workspace mode [#--json-in-workspace-mode]

Single-package mode (`lpm bench`) preserves the runner's stdout. Workspace mode emits a single LPM CLI envelope on stdout; per-member stdout/stderr is captured and surfaced inside the envelope only on failure. See [`lpm lint`](/docs/dev/lint#json-in-workspace-mode) for the exact envelope shape.

## See also [#see-also]

* [`lpm test`](/docs/dev/test) — same auto-detection, for tests
* [Test & bench runners](/docs/dev/test-bench-runners) — how detection works
