Vitest is a fast test runner built on Vite.
The @nx/vitest plugin adds inferred Vitest targets, a project configuration generator, and CI-friendly test splitting.
You can use Vitest with Nx without the plugin and still get task caching, task orchestration, and the project graph.
Requirements
Section titled “Requirements”The @nx/vitest plugin supports the following package versions.
| Package | Supported Versions |
|---|---|
vitest | ^3.0.0 || ^4.0.0 || ^5.0.0 |
Each Vitest major sets its own Vite requirement.
| Vitest | Vite |
|---|---|
| 5 | 6.4 to 8 |
| 4 | 6 to 8 |
| 3 | 5 to 7 |
For Node.js, follow the Nx compatibility matrix rather than the Vitest floor. Nx supports a narrower set of Node versions than Vitest 3 and Vitest 4 accept, so the Nx requirement is the one that applies.
Vitest 5 treats Vite as a peer dependency rather than installing its own copy. If you upgrade from Vitest 4 and your package.json never listed vite, add it. The nx migrate path does this for you.
Nx generators install versions that work together when scaffolding new projects. They pick the highest Vitest major the rest of your workspace supports, so a project on Vite 6.2 gets Vitest 4 rather than a pairing that cannot resolve.
Add to an existing workspace
Section titled “Add to an existing workspace”nx add @nx/vitestVerify inferred tasks
Section titled “Verify inferred tasks”Nx infers Vitest tasks from your Vitest or Vite config files. To confirm which targets were created, open the project details view in Nx Console or run:
nx show project my-appAdd Vitest to a project
Section titled “Add Vitest to a project”Use the configuration generator to set up a project with Vitest:
nx g @nx/vitest:configuration --project=my-appThe generator accepts framework-specific options. Pass the right flags for your project type:
nx g @nx/vitest:configuration --project=my-react-lib --uiFramework=reactSets up Vitest with React JSX support and jsdom test environment.
nx g @nx/vitest:configuration --project=my-vue-lib --uiFramework=vueSets up Vitest with Vue SFC support and jsdom test environment.
nx g @nx/vitest:configuration --project=my-angular-lib --uiFramework=angularConfigures Vitest for Angular with the appropriate test setup.
nx g @nx/vitest:configuration --project=my-node-lib --testEnvironment=nodeUses the node test environment instead of the default jsdom.
See the full configuration generator reference for all options.
Local development
Section titled “Local development”Run Vitest through Nx so caching and the project graph work together.
nx test my-appnx test my-app --watchnx test my-app -- MyComponent.spec.tsnx test my-app --uinx test my-app --coverageConfiguration
Section titled “Configuration”How tasks are inferred
Section titled “How tasks are inferred”The @nx/vitest plugin creates a target for any project that has a Vitest or Vite config file with test settings. The plugin looks for:
vitest.config.jsvitest.config.tsvitest.config.mjsvitest.config.mtsvitest.config.cjsvitest.config.ctsvite.config.js(withtestconfiguration)vite.config.ts(withtestconfiguration)vite.config.mjs(withtestconfiguration)vite.config.mts(withtestconfiguration)vite.config.cjs(withtestconfiguration)vite.config.cts(withtestconfiguration)
The configuration directory must also contain a package.json or project.json. A root Vitest workspace configuration that only orchestrates child projects is not registered as its own project.
To view inferred tasks, open the project details view in Nx Console or run nx show project my-app.
Plugin options
Section titled “Plugin options”Configure the plugin in nx.json:
{ "plugins": [ { "plugin": "@nx/vitest", "options": { "testTargetName": "test", "ciTargetName": "test-ci", "ciGroupName": "Unit Tests (CI)", "testMode": "watch" } } ]}| Option | Type | Default | Description |
|---|---|---|---|
testTargetName | string | test | Name of the test task. |
ciTargetName | string | none | Creates a CI-only task used for atomized runs. |
ciGroupName | string | derived from ciTargetName | Display name for the atomized CI group. |
testMode | watch or run | watch | Determines whether Nx runs vitest (watch) or vitest run (single run). |
discoverTestFiles | glob or vitest | glob | How atomized test files are discovered. glob mirrors Vitest's resolution without booting Vitest per project, which is faster during graph creation. Set to vitest to always enumerate through Vitest. |
When discoverTestFiles is glob, configs that a glob cannot reproduce faithfully still boot Vitest automatically: test.projects or test.workspace (inline or an auto-loaded vitest.workspace.* or vitest.projects.* file), plugins with a configureVitest hook, test.changed or test.related, and enabled browser instances that set their own include, exclude, includeSource, or dir. Patterns the glob reads differently than Vitest trigger the same fallback: an absolute path, a trailing /, or an !(...) extglob, each optionally negated, in include, exclude, includeSource, or typecheck's include or exclude.
The glob path reads the Nx workspace file index, so it never enumerates specs ignored by .gitignore or .nxignore, even ones Vitest itself would run. Set discoverTestFiles to vitest if you need those specs atomized.
There is no single "disable" flag for inference. Use include and exclude to scope which projects each plugin instance applies to.
The test task is cached, with outputs based on your Vitest coverage configuration. Custom reporter output files are not inferred. Set ciTargetName to enable task splitting (Atomizer).
When coverage is enabled, each atomized task writes its report to a directory under the configured reportsDirectory that mirrors the spec file's path. A project reporting to coverage/apps/my-app gets coverage/apps/my-app/src/a.spec.ts/coverage-final.json for the src/a.spec.ts task, so a tool configured with a fixed report path needs a glob instead. Nx inserts the project root before the spec path for a reportsDirectory outside the project, unless the directory already ends with it. ../../reports for apps/my-app gives reports/apps/my-app/src/a.spec.ts. Nx caches only outputs inside the workspace, so atomized tasks and their CI parent run uncached when reportsDirectory resolves outside it.
A target defaults plugin filter for these tasks must use the exact identifier @nx/vitest.
Configure unit and e2e separately
Section titled “Configure unit and e2e separately”If you use Vitest for unit and e2e tests, configure the plugin twice with different include and exclude patterns.
{ "plugins": [ { "plugin": "@nx/vitest", "exclude": ["e2e/**/*"], "options": { "testTargetName": "test", "testMode": "watch" } }, { "plugin": "@nx/vitest", "include": ["e2e/**/*"], "options": { "testTargetName": "e2e", "ciTargetName": "e2e-ci", "ciGroupName": "E2E Tests (CI)", "testMode": "run" } } ]}Set up CI
Section titled “Set up CI”In CI, Nx runs nx affected to rebuild and retest only the projects a change touches, and caches results to skip repeated work.
For a complete pipeline, see Set up CI.