Skip to content

vitest

npm version License: MIT Node.js Vitest

> Base Vitest configuration with TypeScript-friendly defaults, v8 coverage and 80% thresholds.

  • 📊 Coverage: v8 provider with 80% thresholds
  • 🎯 Sensible defaults: Node environment, globals enabled, verbose reporter
  • ⚡ Fast: thread pool by default
  • 🔀 Dual format: ESM and CommonJS builds
Terminal window
npm install --save-dev @jmlweb/vitest-config vitest @vitest/coverage-v8

@vitest/coverage-v8 is needed for --coverage; use the same version as vitest.

> 💡 Upgrading? See the Migration Guide.

vitest.config.ts
import { defineConfig } from 'vitest/config';
import baseConfig from '@jmlweb/vitest-config';
export default defineConfig({
...baseConfig,
});

Everything lives under test. A test key in your config replaces the whole base test block, so spread ...baseConfig.test into it, or use mergeConfig:

import { defineConfig, mergeConfig } from 'vitest/config';
import baseConfig from '@jmlweb/vitest-config';
export default mergeConfig(
baseConfig,
defineConfig({ test: { environment: 'jsdom' } }),
);
import { defineConfig } from 'vitest/config';
import baseConfig from '@jmlweb/vitest-config';
export default defineConfig({
...baseConfig,
test: {
...baseConfig.test,
environment: 'jsdom',
setupFiles: ['./src/test/setup.ts'],
testTimeout: 10000,
},
});
import { defineConfig } from 'vitest/config';
import baseConfig from '@jmlweb/vitest-config';
export default defineConfig({
...baseConfig,
test: {
...baseConfig.test,
coverage: {
...baseConfig.test?.coverage,
thresholds: { lines: 90, functions: 90, branches: 85, statements: 90 },
},
},
});

Import describe, it and expect yourself and report coverage without failing the run:

import { defineConfig } from 'vitest/config';
import baseConfig from '@jmlweb/vitest-config';
export default defineConfig({
...baseConfig,
test: {
...baseConfig.test,
globals: false,
coverage: { ...baseConfig.test?.coverage, thresholds: {} },
},
});
Setting Value
globals true
environment 'node'
testTimeout / hookTimeout 5000 / 10000 ms
pool 'threads'
reporters ['verbose']
include **/*.{test,spec}.{ts,tsx,js,jsx}
exclude node_modules, dist, build, dot-dirs, tool config files
coverage.provider 'v8'
coverage.thresholds 80 for lines, functions, branches, statements
coverage.include src/**/*.{ts,tsx,js,jsx}
coverage.reporter ['text', 'json', 'html']

Coverage excludes *.d.ts, *.config.{ts,js}, dist, build, node_modules, coverage, and test/spec files.

  • ✅ Vitest-based TypeScript projects
  • ✅ Enforced coverage with a shared baseline
  • ✅ Node.js libraries, CLIs and APIs, or browser code with environment: 'jsdom'

Not for you if you use Jest: see @jmlweb/jest-config (maintenance mode).

Spread baseConfig.test and override what you need (see Examples). Install jsdom or happy-dom yourself when you set environment to either.

{
"scripts": {
"test": "vitest",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage",
"test:typecheck": "vitest typecheck"
}
}
Terminal window
npm test # watch mode
npm run test:coverage # single run with coverage

Type checking is not part of the config: run vitest typecheck separately.

  • Node.js >= 22.12.0
  • Vitest >= 1.0.0 (config targets Vitest 4)
  • vitest (>=1.0.0)

Breaking: Node.js >= 22.12.0 is required.

  1. Upgrade Node.js to 22.12.0 or later.
  2. Update: npm install --save-dev @jmlweb/vitest-config@latest

Vitest 4: poolOptions.threads.minThreads and maxThreads are gone; Vitest manages the pool automatically.

See the Changelog for details.

MIT