LPM-cli

lpm bench

Auto-detect and run the project's benchmark runner.

lpm bench [-- args...]

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

Examples

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

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

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

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

Workspaces

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

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

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

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).

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

FlagEffect
--allRun in every workspace member
--filter <expr>Select workspace members by the filter grammar (repeatable)
--filter-prod <expr>Select workspace members with production-only dependency closures
--affectedRun 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-matchExit 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.

--json in workspace mode

Single-package mode (lpm bench) preserves the runner's stdout. Workspace mode emits a single LPM envelope on stdout; per-member stdout/stderr is captured and surfaced inside the envelope only on failure. See lpm lint for the exact envelope shape.

See also