JavaScript & TypeScript · Comparison
Node.js test runner vs Vitest
Use node:test for Node.js code with no build step and Vitest for Vite projects, JSX and DOM tests. Both read V8 coverage, yet reported 82% and 100% of lines.
Node.js test runner or Vitest?
Use the built-in runner, node:test, for Node.js libraries, command-line
tools and services with no build step: it has been stable since Node.js 20
and needs no dependency. Use Vitest when the project already uses Vite, when
tests need JSX or a DOM, or when you want Jest-style matchers and mocks.
The same test in both
const { test } = require('node:test');
const assert = require('node:assert/strict');
const { canAccess } = require('./src/access');
test('signed-out session cannot access', () => {
assert.equal(canAccess(false, false), false);
});import { expect, test } from 'vitest';
import access from './src/access.js';
test('signed-out session cannot access', () => {
expect(access.canAccess(false, false)).toBe(false);
});
Run them with node --test and npx vitest run.
What differs
node:test on Node.js 24 | Vitest 5 | |
|---|---|---|
| Install | Built in | npm install -D vitest |
| Configuration | Command-line flags | Shares Vite’s configuration and plugins |
| Assertions | node:assert | expect, compatible with Jest’s |
| Mocks | mock.fn, mock.timers; module mocks behind a flag | vi.fn, vi.mock, fake timers |
| TypeScript and JSX | Node.js strips types; no JSX | Both, through Vite |
| DOM | Not included | jsdom or happy-dom, or a real browser in Browser Mode |
| Watch mode | --watch, experimental | Built in, reruns what a change affects |
| Coverage | --experimental-test-coverage | --coverage, with a V8 or Istanbul provider |
Sources: the Node.js test runner documentation and Vitest’s feature list.
Both read V8, and the numbers differ
The same three tests on one file, on Node.js 24.21.0 and Vitest 5.0.4:
| Command | Lines | Branches | Functions |
|---|---|---|---|
node --test --experimental-test-coverage | 14/17 (82.35%) | 5/6 (83.33%) | 2/3 (66.67%) |
vitest run --coverage, V8 provider | 5/5 (100%) | 6/7 (85.71%) | 2/2 (100%) |
Both take coverage from the V8 engine. Node.js reports it as V8 gives it:
every line of the file counts, and the /* istanbul ignore next */ comment
above an untested function is not read.
Vitest maps V8’s data onto the source’s syntax tree. It counts statements and honours the comment, and its totals match what Jest’s Babel provider reports for the same file. See Vitest coverage: V8 vs Istanbul.
Coverage in node:test is still marked experimental. It prints a summary and
can write lcov. Vitest writes HTML, lcov, Cobertura and other reports.
Using both
They can share a repository: node:test for a server package with no build
step, Vitest for the packages built with Vite. Name the test files
differently so each runner picks up only its own.
Per-test coverage in either
npx supercov -- node --test
npx supercov -- npx vitest run
Supercov measures both runners per test, with line, branch and MC/DC coverage, and keeps your configuration. On the file above it reported 7/9 lines, 4/6 branches and 1/3 MC/DC conditions under Vitest.
Comparing with Jest instead? See Node.js test runner vs Jest and Vitest vs Jest.
Example evidence: fixture source, commands and recorded results (JSON). Measured October 12, 2026 with Supercov 4.3.0. These small examples are not a performance benchmark or a general conformance test.