···46464747Include the `samples` array of per-iteration timings on every benchmark result. Disabled by default to reduce memory usage; enable when a custom reporter or API consumer needs the raw samples.
48484949+## benchmark.provider
5050+5151+- **Type:** `string`
5252+- **Default:** `undefined` (uses the built-in provider)
5353+5454+The benchmark provider that executes registered benchmarks and returns their results. Set this to a module path whose default export implements `BenchmarkProvider`. Relative paths are resolved from the project root.
5555+5656+See the [Custom Benchmark Provider](/guide/advanced/benchmark-provider) guide for setup instructions and the provider API.
49575058## benchmark.suppressExportGetterWarnings
5159···5361- **Default:** `false`
54625563Suppress the warning printed when a benchmark accesses module export getters too many times. Vitest tracks getter access during benchmark runs because Vite's module runner wraps every export in a getter, and excessive access can dominate the measurement (see [Module Runner Overhead](/guide/benchmarking#module-runner-overhead)). Enable this when you've intentionally accepted the overhead, or when the warning is noisy for benchmarks where the getter cost is negligible.
5656-
+7-5
docs/guide/benchmarking.md
···4455# Benchmarking
6677-Vitest lets you write benchmarks alongside your tests using the `bench` fixture from the [test context](/guide/test-context). Benchmarks are powered by [Tinybench](https://github.com/tinylibs/tinybench) and are defined inside regular `test()` calls, giving you access to the full power of Vitest's test runner: retries, lifecycle hooks, filtering, and assertions.
77+Vitest lets you write benchmarks alongside your tests using the `bench` fixture from the [test context](/guide/test-context). The built-in benchmark provider is powered by [Tinybench](https://github.com/tinylibs/tinybench), and benchmarks are defined inside regular `test()` calls, giving you access to the full power of Vitest's test runner: retries, lifecycle hooks, filtering, and assertions.
8899## Defining a Benchmark
1010···2323The `bench()` function registers a benchmark without executing it. Calling `.run()` runs the benchmark and returns the result. After the test completes, Vitest prints a single-row version of the [comparison table](#comparing-benchmarks) (ops/sec, mean time, percentiles, etc.), so you get the same output for a one-off benchmark as you do for `bench.compare()`.
24242525::: warning
2626-The `bench` fixture is only available in files matched by [`benchmark.include`](/config/#benchmark-include) (default: `**/*.{bench,benchmark}.?(c|m)[jt]s?(x)`). Using `{ bench }` inside a regular test file will throw an error.
2626+The `bench` fixture is only available in files matched by [`benchmark.include`](/config/benchmark#benchmark-include) (default: `**/*.{bench,benchmark}.?(c|m)[jt]s?(x)`). Using `{ bench }` inside a regular test file will throw an error.
27272828Whether a file participates in the benchmark run is decided by the filename, not by whether the test uses the `bench` fixture. Renaming `parser.test.ts` to `parser.bench.ts` (or adjusting `benchmark.include`) is what moves it into the benchmark project.
2929:::
30303131## Running Benchmarks
32323333-Benchmark files are matched by [`benchmark.include`](/config/#benchmark-include) (default: `**/*.{bench,benchmark}.?(c|m)[jt]s?(x)`) and run in their own project, separate from your regular tests. There are three ways to run them, depending on whether you want to skip them, run them alongside tests, or run them on their own.
3333+Benchmark files are matched by [`benchmark.include`](/config/benchmark#benchmark-include) (default: `**/*.{bench,benchmark}.?(c|m)[jt]s?(x)`) and run in their own project, separate from your regular tests. There are three ways to run them, depending on whether you want to skip them, run them alongside tests, or run them on their own.
34343535### `vitest` (default)
36363737-Without [`benchmark.enabled`](/config/#benchmark-enabled), the `vitest` command only runs regular tests. Benchmark files are ignored entirely. This is the default and the right choice for day-to-day development, since benchmarks are slow and noisy and shouldn't run on every save.
3737+Without [`benchmark.enabled`](/config/benchmark#benchmark-enabled), the `vitest` command only runs regular tests. Benchmark files are ignored entirely. This is the default and the right choice for day-to-day development, since benchmarks are slow and noisy and shouldn't run on every save.
38383939### `vitest` with `benchmark.enabled`
4040···7171# only benchmarks whose test name matches "JSON"
7272vitest bench -t JSON
7373```
7474+7575+To execute benchmarks with another benchmarking engine or execution strategy, see the [Custom Benchmark Provider](/guide/advanced/benchmark-provider) guide.
74767577## Comparing Benchmarks
7678···330332331333Benchmarks are inherently flaky: CPU load, thermal throttling, GC pressure, and background processes all affect results. Vitest takes several steps to minimize this noise:
332334333333-- **Separate project**: Benchmark files are grouped into their own project based on the [`benchmark.include`](/config/#benchmark-include) pattern. The `bench` fixture is only exposed in files matched by that pattern. Using it inside a regular test file will throw an error.
335335+- **Separate project**: Benchmark files are grouped into their own project based on the [`benchmark.include`](/config/benchmark#benchmark-include) pattern. The `bench` fixture is only exposed in files matched by that pattern. Using it inside a regular test file will throw an error.
334336- **No concurrency**: Tests within a benchmark file always run sequentially. Benchmark files themselves also run one at a time, never in parallel. This prevents benchmarks from interfering with each other.
335337336338To further improve stability:
+83
docs/guide/advanced/benchmark-provider.md
···11+# Custom Benchmark Provider <Version type="experimental">5.0.0</Version> <Badge type="danger">advanced</Badge> {#custom-benchmark-provider}
22+33+::: warning
44+This is an advanced, experimental API. If you only need to run benchmarks with Vitest's built-in provider, read the [Benchmarking](/guide/benchmarking) guide instead.
55+:::
66+77+Vitest uses a benchmark provider to execute the functions registered with `bench` and convert their measurements into results that Vitest can report. The built-in provider uses [Tinybench](https://github.com/tinylibs/tinybench), but you can replace it to use another benchmarking engine or execution strategy.
88+99+## Setup
1010+1111+Set [`benchmark.provider`](/config/benchmark#benchmark-provider) to the path of your provider module. Relative paths are resolved from the project root.
1212+1313+```ts [vitest.config.ts]
1414+import { defineConfig } from 'vitest/config'
1515+1616+export default defineConfig({
1717+ test: {
1818+ benchmark: {
1919+ provider: './benchmark-provider.ts',
2020+ },
2121+ },
2222+})
2323+```
2424+2525+The module must has a default export with an object that implements `BenchmarkProvider`. This example wraps Tinybench to demonstrate how registrations and results flow through a provider. If you use Tinybench in your provider, add it as a direct dependency of your project.
2626+2727+```ts [benchmark-provider.ts]
2828+import type { BenchmarkProvider } from 'vitest'
2929+import { Bench } from 'tinybench'
3030+3131+const provider = {
3232+ async run({ test, config, registrations, options }) {
3333+ const bench = new Bench({
3434+ signal: test.context.signal,
3535+ retainSamples: config.retainSamples,
3636+ ...options,
3737+ })
3838+3939+ for (const { name, fn, fnOpts } of registrations) {
4040+ bench.add(name, fn, fnOpts)
4141+ }
4242+4343+ await bench.run()
4444+4545+ return bench.tasks.map((task) => {
4646+ const result = task.result
4747+4848+ if (result.state === 'errored') {
4949+ throw result.error
5050+ }
5151+ if (result.state !== 'completed') {
5252+ throw new Error(`Benchmark "${task.name}" ended in the "${result.state}" state`)
5353+ }
5454+5555+ return {
5656+ ...result,
5757+ name: task.name,
5858+ }
5959+ })
6060+ },
6161+} satisfies BenchmarkProvider
6262+6363+export default provider
6464+```
6565+6666+## Provider API
6767+6868+Vitest calls `provider.run(group)` when a registration's `.run()` method is called, or once for all runnable registrations passed to `bench.compare()`. The `group` contains:
6969+7070+- `test`: the test that registered the benchmarks. `test.context.signal` is aborted when the run is cancelled.
7171+- `config`: the resolved benchmark configuration for the current project.
7272+- `registrations`: runnable benchmarks in registration order. Every registration contains `name`, `fn`, and optional `fnOpts` for lifecycle hooks, cancellation, async behavior, and sample retention.
7373+- `options`: benchmark run options passed to `.run()` or `bench.compare()`, if any.
7474+7575+The provider is responsible for honoring the run and registration options and for running every benchmark function and its `beforeAll`, `beforeEach`, `afterEach`, and `afterAll` hooks according to the benchmarking engine's lifecycle. If execution fails, throw the error to fail the test.
7676+7777+`run` must resolve to one `BenchResult` for every runnable registration. Results are matched to registrations by `name` and are the source for `.run()` return values, comparison tables, reporters, and saved benchmark results. A custom engine must convert its measurements into the Tinybench-compatible `BenchResult` shape exported by `vitest`.
7878+7979+Registrations created by `bench.from()` are loaded by Vitest and are not passed to the provider.
8080+8181+## Provider Lifetime
8282+8383+Vitest imports the provider module on first use and caches its default export for the lifetime of the worker. The API does not have separate setup or teardown hooks; keep worker-scoped state on the provider object when needed.
···2929 retainSamples?: boolean
30303131 /**
3232+ * The benchmark provider that executes registered benchmarks and produces
3333+ * their results. Provide a path to a module whose default export implements
3434+ * `BenchmarkProvider`. The path is resolved relative to the project
3535+ * root. If not specified, the built-in provider is used.
3636+ *
3737+ * @experimental
3838+ */
3939+ provider?: string
4040+4141+ /**
3242 * Disable warnings when a benchmark accesses module export getters too many times.
3343 * @default false
3444 */
···4252 * @internal
4353 */
4454 projectName?: string
5555+}
5656+5757+export type ResolvedBenchmarkOptions = Omit<Required<BenchmarkUserOptions>, 'provider'> & {
5858+ provider?: string | undefined
4559}
+3-3
packages/vitest/src/node/types/config.ts
···2020import type { TestSequencerConstructor } from '../sequencers/types'
2121import type { VCSProvider } from '../vcs/vcs'
2222import type { WatcherTriggerPattern } from '../watcher'
2323-import type { BenchmarkUserOptions } from './benchmark'
2323+import type { BenchmarkUserOptions, ResolvedBenchmarkOptions } from './benchmark'
2424import type { BrowserConfigOptions, BrowserServerContribution, ResolvedBrowserOptions } from './browser'
2525import type { CoverageOptions, ResolvedCoverageOptions } from './coverage'
2626import type { Reporter } from './reporter'
27272828export type { CoverageOptions, ResolvedCoverageOptions }
2929-export type { BenchmarkUserOptions }
2929+export type { BenchmarkUserOptions, ResolvedBenchmarkOptions }
3030export type { RuntimeConfig, SerializedConfig } from '../../runtime/config'
3131export type { SequenceHooks, SequenceSetupFiles } from '../../runtime/runner/types'
3232export type { BrowserConfigOptions, BrowserInstanceOption, BrowserScript } from './browser'
···12271227 cliExclude?: string[]
1228122812291229 project: string[]
12301230- benchmark: Required<BenchmarkUserOptions>
12301230+ benchmark: ResolvedBenchmarkOptions
12311231 shard?: {
12321232 index: number
12331233 count: number