NEVER upgrade Vite major versions without checking Node.js compatibility first. Vite 7+ drops Node.js 18 support entirely.
NEVER use build.rollupOptions in Vite 8 -- it is deprecated and mapped internally. ALWAYS use build.rolldownOptions instead.
NEVER use esbuild config in Vite 8 for new projects -- it is deprecated and converted to oxc internally. ALWAYS use the oxc config option.
NEVER use api: 'legacy' for Sass in Vite 7+ -- the legacy Sass API is completely removed. ALWAYS use the modern Sass API.
NEVER use the object form of output.manualChunks in Vite 8 -- it has been removed. ALWAYS use the function form.
ALWAYS add moduleType: 'js' in plugin load/transform hooks when returning non-JS content in Vite 8. Omitting this causes silent failures.
ALWAYS handle BundleError when using the build() API in Vite 8. Raw errors are no longer thrown.
Decision Tree: Which Migration Path?
Upgrading Vite?
├── From v5 → v6?
│ ├── Using Sass? → Switch to modern API (api: 'modern-compiler')
│ ├── Using PostCSS TS config with ts-node? → Switch to tsx or jiti
│ ├── Using json.stringify: true/false? → Review: default is now 'auto'
│ └── Using resolve.conditions? → Review new defaults
│
├── From v6 → v7?
│ ├── On Node.js 18? → MUST upgrade to Node.js 20.19+ or 22.12+
│ ├── Using splitVendorChunkPlugin? → Remove it, use manual chunking
│ ├── Using Sass legacy API? → MUST migrate to modern API
│ └── Using hook-level enforce on transformIndexHtml? → Move to plugin-level
│
├── From v7 → v8?
│ ├── Using build.rollupOptions? → Rename to build.rolldownOptions
│ ├── Using esbuild config? → Rename to oxc config
│ ├── Writing plugins with load/transform? → Add moduleType: 'js'
│ ├── Using object manualChunks? → Convert to function form
│ ├── Using import.meta.url in UMD/IIFE? → Find alternative
│ └── Catching build() errors? → Handle BundleError type
│
└── Multi-version jump (v5 → v8)?
→ Apply changes sequentially: v5→v6, v6→v7, v7→v8
Migration Path: Vite 5 to 6
1. Environment API (Internal Refactoring)
The Environment API restructures Vite internals. Most user-facing code is unaffected, but plugin authors MUST review their hooks.
2. Vite Runtime API Replaced by Module Runner
// BEFORE (v5): Vite Runtime APIimport { createViteRuntime } from'vite'// AFTER (v6): Module Runner APIimport { createServerModuleRunner } from'vite'
3. resolve.conditions Defaults Changed
Vite 6 explicitly defines resolve.conditions defaults. If you relied on implicit conditions, verify your package resolution still works.
4. json.stringify Default Changed to 'auto'
// BEFORE (v5): json.stringify default was false// AFTER (v6): json.stringify default is 'auto' (stringifies files >10kB)// To restore v5 behavior:exportdefaultdefineConfig({
json: { stringify: false },
})
5. PostCSS Config Loader Updated
PostCSS config loading now uses postcss-load-config v6. TypeScript PostCSS configs MUST use tsx or jiti instead of ts-node.
6. Sass Modern API Default
// BEFORE (v5): Legacy API was default// AFTER (v6): Modern API is default// To temporarily use legacy (ONLY in v6, removed in v7):exportdefaultdefineConfig({
css: {
preprocessorOptions: {
scss: { api: 'legacy' },
},
},
})
7. Library CSS Filename Change
Library mode CSS filename now uses the name field from package.json instead of generic style.css.
8. build.cssMinify Enabled for SSR
CSS minification is now enabled by default for SSR builds.
9. CommonJS strictRequires Default Changed
strictRequires now defaults to true (was 'auto'). This may affect CJS dependency resolution.
Lightning CSS is now the default CSS minifier. No configuration needed.
4. Oxc Minifier Default (30-90x Faster Than Terser)
build.minify defaults to 'oxc' for client builds. Terser is still available if explicitly configured.
5. Plugin Authors: moduleType Required
// BEFORE (v7): Return string directlytransform(code, id) {
return { code: transformedCode }
}
// AFTER (v8): MUST specify moduleType for non-JS contenttransform(code, id) {
return { code: transformedCode, moduleType: 'js' }
}
6. build() API Throws BundleError
// BEFORE (v7):try {
awaitbuild()
} catch (e) {
console.error(e.message)
}
// AFTER (v8):try {
awaitbuild()
} catch (e) {
if (e.errors) {
for (const error of e.errors) {
console.log(error.code)
}
}
}
7. Object manualChunks Removed
// BEFORE (v7): Object form allowedmanualChunks: { vendor: ['react', 'react-dom'] }
// AFTER (v8): MUST use function formmanualChunks(id) {
if (id.includes('react')) return'vendor'
}
8. import.meta.url Not Polyfilled in UMD/IIFE
If your library build uses UMD/IIFE format and references import.meta.url, you MUST find an alternative approach.
9. esbuild Is Now Optional
esbuild is no longer a direct dependency. If your plugins require esbuild, ALWAYS install it explicitly: