Nx Vite Integration
Configure and integrate Vite in Nx monorepos for applications and libraries. Covers vite.config.ts setup, framework plugins, TypeScript path resolution, asset copying, library mode builds, and Vitest integration. Use when: adding Vite to an Nx project, migrating from Webpack, configuring Vitest, fixing tsconfig path resolution, or setting up library mode. Triggers: "add vite", "nx vite", "vite setup", "vite.config.ts", "vitest config", "library mode", "nxViteTsPaths", "copy assets", "vite path aliases", "migrate webpack to vite" Examples: - user: "Add Vite to this Nx app" -> install plugin and configure vite.config.ts - user: "Vitest is failing in Nx" -> fix test config and cache/coverage paths - user: "Path aliases break in Vite" -> add nxViteTsPaths plugin - user: "Set up Vite for my Nx library" -> configure lib mode + dts + externals
npx skills add github:pantheon-org/tekhne --skill repository-mgmt--nx--vite-integrationConfigure Vite as the build tool in Nx workspaces with predictable, cache-friendly defaults.
Mindset
Nx and Vite each have their own opinions about project structure. The integration works by making Vite defer to Nx for path resolution and task orchestration while Nx defers to Vite for bundling. The critical bridge is nxViteTsPaths() — without it, workspace path aliases silently resolve to nothing and builds fail with cryptic module-not-found errors.
Think in two layers: workspace-level (Nx executor targets, cache dirs, project boundaries) and build-level (Vite plugins, rollup options, output formats). Workspace-level decisions live in project.json; build-level decisions live in vite.config.ts. Keep them separate and each layer becomes predictable.
Library mode differs meaningfully from app mode: apps bundle everything together, libraries externalize peer deps to avoid duplication in consumers. The distinction determines whether rollupOptions.external and vite-plugin-dts are needed.
When to Use
| Scenario | Use This Skill |
|---|---|
| Adding Vite to an existing Nx app or lib | Yes |
| Migrating from Webpack or CRA to Vite inside Nx | Yes |
| Setting up Vitest alongside an existing Vite config | Yes |
Fixing @org/lib path aliases failing in Vite builds |
Yes |
Configuring library mode (build.lib) with DTS output |
Yes |
| Setting up a standalone Vite project (no Nx) | No — use Vite docs directly |
| Adding a non-Vite bundler (esbuild standalone, Rollup) | No — this skill is Nx + Vite specific |
Workflow
Step 1: Install Dependencies
Preconditions:
- Nx workspace exists
- Node.js 18+ and package manager available
Commands:
bunx nx add @nx/vite
bun add -d vite
Framework plugin (choose one):
bun add -d @vitejs/plugin-react
# or
bun add -d @vitejs/plugin-vue
# or
bun add -d @sveltejs/vite-plugin-svelte
Expected result:
@nx/viteand framework plugin installed
Step 2: Generate or Configure Vite
Preconditions:
- Dependencies installed
- Target project exists in Nx
Recommended command:
bunx nx g @nx/vite:configuration <project-name>
Manual baseline (vite.config.ts):
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
export default defineConfig({
root: __dirname,
plugins: [react(), nxViteTsPaths()],
});
Expected result:
vite.config.tsexists and resolves workspace path aliases
Step 3: Configure Nx Targets
Preconditions:
- Vite config exists
Ensure target config supports:
buildservetest(Vitest)
Expected result:
nx run <project>:buildandnx run <project>:testare valid targets
Step 4: Add Project-Specific Features
For apps:
- Set
outDirandcacheDirrelative to workspace root - Add
nxCopyAssetsPluginif non-public files must be copied - Add environment replacement plugin when needed
For libraries:
- Configure
build.lib - Externalize peer deps in
rollupOptions.external - Add
vite-plugin-dtsfor declaration output
Expected result:
- Build outputs to
dist/with correct dependency boundaries
Step 5: Verify Setup
Commands:
bunx nx run <project>:build
bunx nx run <project>:test
Expected result:
- Build succeeds
- Tests run with configured environment and cache directories
Anti-Patterns
NEVER: Skip nxViteTsPaths() in Nx Monorepos
Why:
- Workspace path aliases (
@org/lib) fail without Nx path plugin integration.
Bad:
export default defineConfig({
plugins: [react()],
});
Good:
export default defineConfig({
plugins: [react(), nxViteTsPaths()],
});
NEVER: Bundle All Dependencies in Library Mode
Why:
- Bloats bundles and breaks consumer-side tree shaking.
Bad:
build: {
lib: { entry: 'src/index.ts' },
}
Good:
build: {
lib: { entry: 'src/index.ts' },
rollupOptions: {
external: ['react', 'react-dom', /^@my-org\//],
},
}
NEVER: Use Project-Relative Cache/Coverage Paths that Ignore Workspace Root
Why:
- Nx caching and output tracking become inconsistent across projects.
Bad:
test: {
cache: { dir: './node_modules/.vitest' },
coverage: { reportsDirectory: './coverage' },
}
Good:
test: {
cache: { dir: '../../node_modules/.vitest/apps/my-app' },
coverage: { reportsDirectory: '../../coverage/apps/my-app' },
}
NEVER: Mix Unrelated Build and Test Concerns Without Intention
Why:
- Large mixed configs become hard to debug and maintain.
Bad:
- One growing config with ad-hoc overrides and no sectioning.
Good:
- Keep sections intentional (
build,server,test, plugins) and validate each step.
Constraint Guidelines
Hard Constraints
- Always include
nxViteTsPaths()in Nx monorepos - Always set
root: __dirname - Always configure
outDirandcacheDirrelative to workspace root - Always externalize peer dependencies for published libraries
- Always define
test.reporters,test.environment, and deterministic cache/coverage paths
Flexible Choices
- Framework plugin (React, Vue, Svelte, Solid, etc.)
- Output formats (
es,cjs,umd) based on consumers - CSS tooling (PostCSS, Tailwind, vanilla)
- DTS strictness (
skipDiagnostics: true/false) based on CI strategy
Verification Commands
bunx nx run <project>:build
bunx nx run <project>:test
bunx @biomejs/biome check skills/nx-vite-integration/
rumdl check skills/nx-vite-integration
References
- Vite Config Patterns — vite.config.ts options, plugin setup, and resolver configuration for Nx projects
- Nx Vite Plugins —
@nx/viteexecutor options, inferred task configuration, and caching setup - Library Mode —
build.libconfiguration, entry point patterns, and DTS generation - Vitest Integration — Vitest configuration, coverage providers, and Nx test executor setup
- Troubleshooting — common Vite + Nx errors, path resolution failures, and DTS issues
Explicit NEVER/WHY/consequence triplets with side-by-side bad/good examples. Generic warnings score low — concrete failure modes with real impact (security, correctness, performance) score high.
Runtime validation via eval scenarios proving the skill actually changes agent behaviour. Requires evals/ directory, instructions.json, ≥3 scenarios, and ≥80% instruction coverage in summary.json.
Appropriate rigidity for the skill type: strict rules for critical/security skills, balanced steps for process skills, flexible options for tool skills. Mismatched calibration (too rigid or too loose) reduces score.
Expert-only knowledge the AI couldn't derive on its own — domain-specific patterns, production gotchas, decision frameworks, and non-obvious tool behaviour. High scores mean <5% redundancy with what the model already knows.
A clear philosophy plus numbered step-by-step workflows with explicit entry/exit points. Should answer: what is the core principle, how to execute it, and when (and when not) to apply it.
Rich activation keywords and trigger scenarios in the description so the skill fires when needed. Best descriptions read like an exhaustive list of the tasks and concepts that should invoke this skill.
Copy-paste-ready code, complete runnable examples, real file paths and commands. Pseudocode and abstract descriptions score low — concrete, executable content scores high.
SKILL.md as a <100-line navigation hub pointing to focused references/ files. Content should be lazy-loaded on demand, not front-loaded. Includes actionable 'When to Use' conditions per reference.
Proper frontmatter, single-task focus, activation keywords, and cross-harness portability. Skills must work across 40+ agentic harnesses without hardcoded paths or agent-specific references.
Expert-only knowledge the AI couldn't derive on its own — domain-specific patterns, production gotchas, decision frameworks, and non-obvious tool behaviour. High scores mean <5% redundancy with what the model already knows.
A clear philosophy plus numbered step-by-step workflows with explicit entry/exit points. Should answer: what is the core principle, how to execute it, and when (and when not) to apply it.
Explicit NEVER/WHY/consequence triplets with side-by-side bad/good examples. Generic warnings score low — concrete failure modes with real impact (security, correctness, performance) score high.
Proper frontmatter, single-task focus, activation keywords, and cross-harness portability. Skills must work across 40+ agentic harnesses without hardcoded paths or agent-specific references.
SKILL.md as a <100-line navigation hub pointing to focused references/ files. Content should be lazy-loaded on demand, not front-loaded. Includes actionable 'When to Use' conditions per reference.
Appropriate rigidity for the skill type: strict rules for critical/security skills, balanced steps for process skills, flexible options for tool skills. Mismatched calibration (too rigid or too loose) reduces score.
Rich activation keywords and trigger scenarios in the description so the skill fires when needed. Best descriptions read like an exhaustive list of the tasks and concepts that should invoke this skill.
Copy-paste-ready code, complete runnable examples, real file paths and commands. Pseudocode and abstract descriptions score low — concrete, executable content scores high.
No eval scenarios available.
Library Mode Guide
Build Nx libraries with Vite while preserving consumer flexibility.
Minimal Library Mode
build: {
outDir: '../../dist/libs/my-lib',
lib: {
entry: 'src/index.ts',
name: 'MyLib',
fileName: 'index',
formats: ['es'],
},
rollupOptions: {
external: ['react', 'react-dom', 'react/jsx-runtime'],
},
}
Multi-Format Output
build: {
lib: {
entry: 'src/index.ts',
name: 'MyLib',
fileName: (format) => `index.${format}.js`,
formats: ['es', 'cjs'],
},
}
DTS Plugin Setup
Install:
bun add -d vite-plugin-dts
Fast mode (type checks elsewhere):
import dts from 'vite-plugin-dts';
import { join } from 'path';
plugins: [
dts({
entryRoot: 'src',
tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'),
skipDiagnostics: true,
}),
]
Strict mode (block on type errors):
plugins: [
dts({
root: '../../',
entryRoot: 'libs/my-lib/src',
tsConfigFilePath: 'libs/my-lib/tsconfig.lib.json',
include: ['libs/my-lib/src/**/*.ts'],
outputDir: 'dist/libs/my-lib',
skipDiagnostics: false,
}),
]
Externalization Rules
Always externalize:
- Peer dependencies
- Runtime deps expected from consumer environment
Pattern:
rollupOptions: {
external: ['react', 'react-dom', /^@my-org\//],
}
Avoid:
- Shipping bundled React into publishable UI libraries
- Omitting
externalentirely for shared libraries
Nx Vite Plugin Reference
Core Nx-specific plugins for Vite projects.
nxViteTsPaths
Import:
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
Purpose:
- Resolves workspace TypeScript path aliases in monorepos.
Use:
plugins: [react(), nxViteTsPaths()]
When required:
- Any Nx workspace with cross-project imports (
@scope/lib).
nxCopyAssetsPlugin
Import:
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
Purpose:
- Copies non-public assets into output during build.
Use:
plugins: [nxCopyAssetsPlugin(['*.md', 'LICENSE'])]
Notes:
public/files are already handled by Vite without this plugin.- Use for files outside standard public asset flow.
replaceFiles (Rollup Replace Files Plugin)
Import:
import { replaceFiles } from '@nx/vite/plugins/rollup-replace-files.plugin';
Purpose:
- Replaces files for environment-specific builds.
Use:
plugins: [
replaceFiles([
{
replace: 'apps/web/src/environments/environment.ts',
with: 'apps/web/src/environments/environment.prod.ts',
},
]),
]
Plugin Ordering Guidance
Suggested order:
- Framework plugin (
react,vue,svelte) nxViteTsPaths()- Asset/environment plugins
- DTS plugin (for libraries)
Reason:
- Framework and path resolution should stabilize module graph before output-time plugins.
Troubleshooting
Common Nx + Vite issues and direct fixes.
TypeScript Paths Not Resolving
Symptoms:
- Imports like
@my-org/libfail during dev/build.
Fix:
- Add
nxViteTsPaths()toplugins. - Confirm project
tsconfigpath aliases are correct.
Build Output in Wrong Directory
Symptoms:
- Artifacts appear inside project folder or unexpected dist path.
Fix:
- Set
root: __dirname. - Set
build.outDirrelative to workspace root (not project root).
Library Types Missing for Consumers
Symptoms:
- Published package compiles but downstream TS projects fail type lookup.
Fix:
- Add
vite-plugin-dtsand verify output. - Ensure package metadata points to types (
types/exports).
Assets Not Copied
Symptoms:
- Markdown/license/static files missing from output.
Fix:
- Use
nxCopyAssetsPlugin([...])for non-public files. - Keep
public/assets in Vite public flow.
Tests Not Running or Cached Correctly
Symptoms:
- Vitest behaves inconsistently between local and CI.
Fix:
- Set
test.reporters,test.environment, and deterministic cache/coverage dirs. - Validate with
nx run <project>:test.
Slow Library Builds
Symptoms:
- Build times grow significantly after adding DTS generation.
Fix:
- Set
skipDiagnostics: truein local development. - Keep strict diagnostics in CI or release checks.
Migration Regressions from Webpack
Symptoms:
- Feature parity gaps after moving to Vite.
Fix:
- Identify Webpack-only behavior first.
- Replace loader/plugin behavior with Vite equivalents incrementally.
- Stop migration for unsupported critical features.
Vite Config Patterns (Nx)
Use these patterns when creating vite.config.ts for Nx apps and libraries.
App Baseline (React)
/// <reference types='vitest' />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
export default defineConfig({
root: __dirname,
cacheDir: '../../node_modules/.vite/apps/my-app',
plugins: [react(), nxViteTsPaths()],
build: {
outDir: '../../dist/apps/my-app',
reportCompressedSize: true,
commonjsOptions: { transformMixedEsModules: true },
},
server: { port: 4200, host: 'localhost' },
preview: { port: 4300, host: 'localhost' },
});
App Baseline (Vue)
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
export default defineConfig({
root: __dirname,
plugins: [vue(), nxViteTsPaths()],
cacheDir: '../../node_modules/.vite/apps/my-app',
build: { outDir: '../../dist/apps/my-app' },
});
App Baseline (Svelte)
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
export default defineConfig({
root: __dirname,
plugins: [svelte(), nxViteTsPaths()],
cacheDir: '../../node_modules/.vite/apps/my-app',
build: { outDir: '../../dist/apps/my-app' },
});
Proxy Pattern
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
}
Environment Replacement Pattern
import { replaceFiles } from '@nx/vite/plugins/rollup-replace-files.plugin';
plugins: [
replaceFiles([
{
replace: 'apps/my-app/src/environments/environment.ts',
with: 'apps/my-app/src/environments/environment.prod.ts',
},
]),
]
Path Depth Rule
Always compute paths from project root to workspace root:
apps/my-appandlibs/my-libusually use../../packages/pkgmay use../
Example mapping:
| Project | cacheDir | outDir |
|---|---|---|
apps/my-app |
../../node_modules/.vite/apps/my-app |
../../dist/apps/my-app |
libs/my-lib |
../../node_modules/.vite/libs/my-lib |
../../dist/libs/my-lib |
packages/pkg |
../node_modules/.vite/packages/pkg |
../dist/packages/pkg |
Vitest Integration (Nx)
Use deterministic Vitest config that works with Nx caching and coverage outputs.
Baseline Test Config
import { defineConfig } from 'vite';
export default defineConfig({
test: {
reporters: ['default'],
globals: true,
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
cache: {
dir: '../../node_modules/.vitest/apps/my-app',
},
coverage: {
provider: 'v8',
reportsDirectory: '../../coverage/apps/my-app',
},
},
});
Environment Selection
jsdom: UI components, browser APIsnode: backend logic, utility librarieshappy-dom: alternative DOM runtime
Required Nx-Friendly Settings
reporters: keep explicit (['default'])cache.dir: workspace-relative pathcoverage.reportsDirectory: workspace-relative path
Separate Config Option
If test concerns become large, use a dedicated vitest.config.ts and keep vite.config.ts focused on build/serve.
Validation Commands
bunx nx run <project>:test
bunx nx run <project>:test --coverage