Jest has been the standard JavaScript testing framework for a decade. It works. It is also slow, has awkward ESM support, and shows its age in 2026.
Vitest is the modern alternative. Built on Vite, native ESM, faster startup, faster watch mode, compatible API. After migrating several client projects, I am not going back to Jest for new work. Here is why and how.
Why switch
Three things make Vitest worth the migration.
1. Speed
Jest's startup is slow. Every test file goes through Babel or SWC transforms, then Jest boots a worker, then tests run. On a project with 200 tests, cold runs take 12-15 seconds.
Vitest uses Vite's transform pipeline. esbuild handles TypeScript and JSX in milliseconds. Native ESM means no transform needed for module resolution. The same 200 tests run in 5-7 seconds.
Watch mode is even more dramatic. Jest re-runs affected tests in 1-2 seconds. Vitest does it in under 200ms.
2. Native ESM
Jest treats ESM as a special case. You configure transformIgnorePatterns, deal with .mjs extensions, and hope your dependencies work. Some do not.
Vitest is ESM-native. import just works. Your dependencies' ESM versions are loaded directly. No transforms, no workarounds, no moduleNameMapper for .mjs.
3. Vite integration
If you already use Vite (most modern React, Vue, Solid, Svelte projects do), Vitest reads your existing vite.config.ts. Same aliases, same env variables, same transforms. Zero duplicate configuration.
For Next.js projects, you add a small vitest.config.ts that points at your setup. The Next.js aliases resolve correctly.
The migration
Most Jest tests work in Vitest with minimal changes.
Step 1: Install Vitest
npm install -D vitest @vitest/coverage-v8 @testing-library/jest-domRemove Jest:
npm uninstall jest @types/jestStep 2: Add a config
For a Vite project:
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./test/setup.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
},
},
})For a Next.js project, add Vite plugin for React:
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./test/setup.ts'],
},
resolve: {
alias: {
'@': path.resolve(__dirname, './'),
},
},
})Step 3: Update setup files
Most Jest setup files import from @testing-library/jest-dom:
// test/setup.ts
import '@testing-library/jest-dom/vitest'The Vitest version of the import path. Everything else in your setup file should work unchanged.
Step 4: Rename jest to vi
// Before
import { jest } from '@jest/globals'
jest.mock('./api', () => ({
fetchUser: jest.fn().mockResolvedValue({ id: 1 }),
}))
const mockFn = jest.fn()
// After
import { vi } from 'vitest'
vi.mock('./api', () => ({
fetchUser: vi.fn().mockResolvedValue({ id: 1 }),
}))
const mockFn = vi.fn()With globals: true, you can also use vi without importing it, like Jest's jest global.
Step 5: Update package.json scripts
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
}
}Step 6: Test and fix edge cases
Most tests pass after renaming. Common edge cases:
jest.useFakeTimers()— works asvi.useFakeTimers(), behavior is similar.- Snapshot tests — Vitest has its own snapshot format that is mostly compatible. Re-generate snapshots with
vitest run -u. - Custom environments — Jest's
@jest/environment-nodebecomesvitest-environment-node. jest.config.js— most options have Vitest equivalents. Some advanced options do not exist.
Features Vitest has that Jest does not
In-source testing
Write tests inside your source files alongside the implementation:
// math.ts
export function add(a: number, b: number) {
return a + b
}
if (import.meta.vitest) {
const { it, expect } = import.meta.vitest
it('adds', () => {
expect(add(1, 2)).toBe(3)
})
}The import.meta.vitest block is stripped from production builds. You get co-located tests without shipping test code.
Browser mode
Run your tests in a real browser using WebDriverIO or Playwright under the hood. Useful for catching browser-specific bugs that jsdom cannot catch.
UI mode
vitest --uiOpens a browser-based UI showing your tests, their output, and the timeline. Great for debugging failing tests interactively.
Better error messages
Vitest's error output shows inline diffs, syntax-highlighted code context, and source maps that actually work. Jest's output is fine. Vitest's is genuinely better.
Features Jest has that Vitest does not (mostly)
A few things to be aware of:
- Custom runtime require hooks — Vitest uses Vite's module system, not CommonJS runtime hooks. Most use cases have Vite equivalents.
- Some legacy reporters — Vitest has its own reporter API. Custom Jest reporters need to be ported.
- Circus / Jasmine integrations — Vitest does not support these legacy test runners.
For 95 percent of projects, none of this matters. For unusual setups, audit before migrating.
Should you migrate?
For new projects: Vitest, no question.
For existing projects: migrate when you have a window of time. The migration is mostly mechanical. The speed gain is real, especially in watch mode during development. Developers notice the difference immediately.
If your Jest setup is heavily customized with workarounds for ESM, transforms, or .mjs resolution, Vitest will save you ongoing pain. If your Jest setup is simple and works, the migration is lower priority but still worthwhile.
Vitest is what Jest would be if it were built in 2026. Faster, simpler, ESM-native. Switch for new projects, migrate existing ones when you have the time.
Want help migrating to Vitest?
I migrate Next.js, React, and Vite projects from Jest to Vitest. Let's talk.
Frequently Asked Questions
Is Vitest faster than Jest?
Yes, significantly. Vitest uses Vite's native ESM and esbuild transforms, so tests start in milliseconds instead of seconds. Watch mode is much more responsive. On a typical project with 200 tests, Vitest runs in half the time Jest takes.
Can Vitest run Jest tests?
Mostly yes. Vitest exports a vi global compatible with the jest global. Rename jest.mock to vi.mock, jest.fn to vi.fn, and most tests work. Some advanced features (like jest's custom environments) require different APIs.
Does Vitest work with Next.js?
Yes. Vitest works with any project that uses Vite for bundling or has a vitest.config.ts. For Next.js specifically, the testing-library docs cover setup. Most Next.js teams have migrated or are migrating.
Should I migrate from Jest to Vitest in 2026?
For new projects, use Vitest. For existing projects, migrate when you have time. The migration is mostly mechanical (rename jest to vi, update config). The speed and ESM benefits are worth it for active codebases.