· vitest / bun / testing

Vitest vs Bun Test — Speed vs Ecosystem

Bun's test runner boots 11× faster than Vitest. But if your suite uses __mocks__ directories, Istanbul coverage, or @vitest/ui, you'll lose more than you gain. Here's when to switch and when to stay.

By

1,050 words · 6 min read

Use Bun test for greenfield TypeScript projects with straightforward mocking. Stay on Vitest if your suite has __mocks__ directories, needs Istanbul coverage, or relies on the @vitest/ui dashboard. The cold-start gap is real — 11× — but it disappears fast once you hit Bun’s compatibility ceiling.

Who this is for

Mid-level developers evaluating whether to migrate an existing Vitest suite to Bun, or choosing a test runner for a new TypeScript project. If you’re on Jest, this also applies — but migration paths from Jest to Bun and from Vitest to Bun are different in a few places.

What we tested

Bun 1.3.14 (released 2026-05-13) · Vitest latest (requires Vite ≥6.0.0, Node ≥20.0.0). Benchmark: 50 tests across 10 TypeScript files with mocking, via PkgPulse 2026. The PkgPulse suite is a standard micro-benchmark — not a production test graph. Real-world timings depend on your machine class, transform cost, DOM setup, and database containers.

Cold start: Bun wins, clearly

RunnerCold start (50 tests, 10 files, TS + mocking)
Bun test0.08 s
Vitest0.9 s
Jest1.2 s

Bun is ~11× faster than Vitest on cold start. That number is from a micro-benchmark, but the direction holds across PkgPulse’s more complex suites too.

Watch mode: closer than you’d think

RunnerWatch re-runMethod
Vitest~40 msHMR: re-runs only affected tests
Bun test~50 msRe-runs the matched set

Ten milliseconds sounds negligible, and for small suites it is. The difference grows in large monorepos where Vitest’s HMR intelligence — re-running only tests transitively affected by the changed file — compounds. Bun runs everything that matched the filter again, every time.

Mocking: Bun’s biggest gap

Both runners cover the standard mocking surface: jest.fn(), spyOn(), module mocking, snapshot testing, and fake timers.

What Bun does not support:

  • __mocks__ directory auto-mocking — Bun’s docs are explicit: not supported yet (Bun mocking docs). Teams that migrated from Jest using the __mocks__ pattern cannot switch to Bun without refactoring.
  • vi.mock() hoisting — Bun requires a --preload workaround for manual module mocking at the top of test files. Different mental model than Vitest’s transparent hoisting.
  • Per-file mock isolation — by default, mock.module() overrides bleed across test files in the same test run.

If your suite uses __mocks__, treat this as a hard blocker. If it doesn’t, mocking is a migration cost, not a wall.

Coverage: Vitest is the deeper option

FeatureVitestBun test
V8-based coverageBuilt-in (custom, not V8 inspector)
Istanbul-based coverage
HTML report
LCOV output
UI-integrated coverage✅ (@vitest/ui)
Threshold enforcement✅ (bunfig.toml)

Bun coverage does the job for CI gating — --coverage gives you text + LCOV, which feeds Codecov and Coveralls without issue. But if your pipeline uses Istanbul for Cloudflare Workers tests (Bun’s coverage provider doesn’t run in CF’s V8 isolate), you’re locked to Vitest + @vitest/coverage-istanbul. HTML reports are also absent — no in-browser coverage view without an external LCOV-to-HTML tool.

DX tooling: @vitest/ui has no Bun equivalent

@vitest/ui is a browser-based dashboard — interactive test tree, dependency graph, inline coverage, pass/fail filtering. Install with npm i -D @vitest/ui, run with vitest --ui.

Bun’s test reporter formats are dots and junit; coverage output formats are text (default) and lcov. Nothing interactive. If your team has built a workflow around the UI dashboard, there’s no drop-in replacement on the Bun side.

One area where Bun is better out of the box: GitHub Actions annotations. Bun auto-detects the GHA environment and emits inline test failure annotations — zero config. Vitest needs a separate reporter plugin.

CI/CD setup

Bun (GitHub Actions):

- uses: oven-sh/setup-bun@v2
- run: bun install
- run: bun test

Vitest (GitHub Actions):

- uses: actions/setup-node@v4
  with: { node-version: '20' }
- run: npm ci
- run: npx vitest run

Three lines vs four. Bun also ships official Docker images (oven/bun). Neither has a real setup cost for most teams.

Migration cost

TaskEffort
Basic test files (no mocks)Trivial — same describe/test/expect API
Replace import from 'vitest'import from 'bun:test'Low — search/replace
Migrate vi.mock()mock.module()Medium — different hoisting model, --preload needed
Migrate __mocks__ directoryHigh / Blocker — unsupported, manual refactor required
Migrate @vitest/coverage-v8Low — flag change, LCOV-compatible
Migrate @vitest/uiN/A — no Bun equivalent
Migrate Istanbul coverageHigh — not supported in Bun

Verdict

Pick Bun test if: new TypeScript project, minimal or no __mocks__ patterns, don’t need @vitest/ui, and cold-start speed matters to your feedback loop. The 11× cold-start gap is real, and Bun 1.3.14 is solid for projects that don’t push its compatibility edges.

Stay on Vitest if: your project has __mocks__ directories (unsupported in Bun — manual refactor required), depends on Istanbul coverage (Cloudflare Workers, Bun runtime environments not covered by Bun’s native coverage), or uses @vitest/ui. Both the __mocks__ gap and the Istanbul gap are documented migration blockers; Vitest’s ecosystem depth is the safer default until Bun resolves them.

If you’re on Vitest and everything works, Bun’s speed gains don’t justify the migration cost unless you’ve measured your test suite and found startup to be the actual bottleneck.

Caveats

Benchmarks are from PkgPulse’s 2026 suite (50 tests, 10 TypeScript files, mocking). Your real-world results depend on test count, transform cost, DOM setup, network calls, and CI machine class. Benchmark your own suite before migrating. Neither Vitest nor Bun is an affiliate partner — no commission involved in this verdict.

References

  1. Bun Test Runner Docs
  2. Bun Mocks Docs
  3. Bun Coverage Docs
  4. Bun Fake Timers Reference
  5. Bun Blog — v1.2 Release
  6. Bun Blog — v1.3.14
  7. Vitest Getting Started
  8. Vitest Coverage Guide
  9. Vitest UI Guide
  10. PkgPulse Benchmark 2026
  11. Socket.dev — Bun 1.2 Node.js Compatibility