# 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. Web page: https://supercov.com/compare/node-test-vs-vitest · Published 2026-10-12 All Supercov pages for agents: https://supercov.com/llms.txt · Full text: https://supercov.com/llms-full.txt ## 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 ```js 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); }); ``` ```js 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](https://nodejs.org/docs/latest-v24.x/api/test.html) documentation and Vitest's [feature list](https://vitest.dev/guide/features). ## 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](https://supercov.com/compare/vitest-coverage.md). 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 ```sh 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](https://supercov.com/compare/node-test-vs-jest.md) and [Vitest vs Jest](https://supercov.com/compare/vitest-vs-jest.md). Example evidence: [fixture source, commands and recorded results (JSON)](https://supercov.com/downloads/tool-comparisons-2026-10-12.json). Measured October 12, 2026 with Supercov 4.3.0. These small examples are not a performance benchmark or a general conformance test.