Vite v8.0.8 — Next-generation frontend build tool powered by native ES modules. Created by Evan You, Vite delivers lightning-fast dev server startup, instant Hot Module Replacement, and optimized production builds via Rolldown.
This guide covers everything you need to install, configure, and use Vite effectively across all supported frameworks and environments.
1. Quick Start
Create a New Project
The fastest way to start is with create-vite, Vite's official scaffolding tool:
npm create vite@latest my-app
This launches an interactive prompt to select a framework and variant. To skip the prompts, pass a template directly:
npm create vite@latest my-app -- --template react-ts
Expected output:
Scaffolding project in /path/to/my-app...
Done. Now run:
cd my-app
npm install
npm run dev
Start Development
cd my-app
npm install
npm run dev
Expected output:
VITE v8.0.8 ready in 237 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
Open http://localhost:5173/ in your browser. Edit any source file and watch changes appear instantly.
Build for Production
npm run build
Expected output:
vite v8.0.8 building for production...
✓ 42 modules transformed.
dist/index.html 0.46 kB │ gzip: 0.30 kB
dist/assets/index-BfH3kQ2f.css 1.42 kB │ gzip: 0.74 kB
dist/assets/index-DiwrgTda.js 143.36 kB │ gzip: 46.10 kB
✓ built in 1.23s
Preview the Build
npm run preview
Expected output:
➜ Local: http://localhost:4173/
➜ Network: use --host to expose
Tip
The
create-viteCLI is also available ascva. Both binary names work identically:npx cva my-app --template vue-ts.
2. Installation
System Requirements
| Requirement | Version |
|---|---|
| Node.js | ^20.19.0 or >=22.12.0 |
| Package manager | npm, yarn, pnpm, or bun |
| OS | Windows, macOS, Linux |
Important
Vite v8 requires Node.js 20.19.0+ or 22.12.0+. Older Node.js versions (16, 18, odd-numbered) are not supported. Check your version with
node --version.
Install via Package Manager
npm
npm create vite@latest my-project
cd my-project
npm install
yarn
yarn create vite my-project
cd my-project
yarn
pnpm
pnpm create vite my-project
cd my-project
pnpm install
bun
bun create vite my-project
cd my-project
bun install
Add Vite to an Existing Project
Install Vite as a dev dependency:
npm install -D vite
Create a minimal index.html at the project root:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
Add scripts to package.json:
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
Scaffolding Templates
create-vite ships with templates for every major framework:
| Framework | Templates |
|---|---|
| Vanilla | vanilla, vanilla-ts |
| Vue | vue, vue-ts |
| React | react, react-ts, react-compiler, react-compiler-ts |
| Preact | preact, preact-ts |
| Lit | lit, lit-ts |
| Svelte | svelte, svelte-ts |
| Solid | solid, solid-ts |
| Qwik | qwik, qwik-ts |
| Ember | ember (TypeScript/JavaScript via ember-cli) |
| Angular | angular |
| Marko | marko (via marko run) |
Community-maintained variants are also available during interactive scaffolding:
| Framework | Community variants |
|---|---|
| Vue | custom-create-vue, Nuxt, Vike |
| React | RSC, React Router, TanStack Router, RedwoodSDK, Vike |
| Svelte | SvelteKit |
| Solid | TanStack Router, Vike |
| Qwik | Qwik City |
| Angular | Analog |
create-vite CLI Options
| Option | Description |
|---|---|
-t, --template NAME |
Use a specific template (skip framework prompt) |
-i, --immediate |
Install dependencies and start dev server automatically |
--interactive / --no-interactive |
Force or disable interactive prompts |
--overwrite |
Overwrite existing target directory |
-h, --help |
Display help |
Example with all options:
npm create vite@latest my-app -- --template react-ts --immediate --overwrite
This creates the project, installs dependencies, and starts the dev server in one command.
3. Configuration
Config File
Vite reads configuration from vite.config.js (or vite.config.ts) at the project root. Use the defineConfig helper for IntelliSense:
import { defineConfig } from 'vite'
export default defineConfig({
// options
})
TypeScript config files work out of the box:
import { defineConfig } from 'vite'
export default defineConfig({
// full type support
})
Essential Options
Base Path
Set the public base path for deployment to a subdirectory:
export default defineConfig({
base: '/my-app/',
})
Public Directory
Static assets in publicDir are served at root and copied to the build output as-is:
export default defineConfig({
publicDir: 'public', // default
})
Files in public/ are accessible at /filename — they are never processed by Vite.
Resolve Aliases
Map import paths to directories:
import { defineConfig } from 'vite'
import path from 'node:path'
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'~components': path.resolve(__dirname, './src/components'),
},
},
})
Usage in source:
import App from '@/App.vue'
import Button from '~components/Button.jsx'
Plugins
Add plugins as an array:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})
Compile-Time Constants
Replace global constants at build time:
export default defineConfig({
define: {
__APP_VERSION__: JSON.stringify('1.2.3'),
'process.env.NODE_ENV': JSON.stringify('production'),
},
})
Use in source code:
console.log(`Running version ${__APP_VERSION__}`)
Dev Server Configuration
export default defineConfig({
server: {
host: '0.0.0.0', // listen on all interfaces
port: 3000, // custom port
strictPort: true, // fail if port is taken
open: true, // open browser on start
cors: true, // enable CORS
headers: { // custom response headers
'X-Custom-Header': 'value',
},
hmr: {
overlay: true, // show error overlay (default)
},
forwardConsole: {
enabled: true, // forward browser console to terminal
},
fs: {
strict: true, // restrict file serving to workspace
allow: [
'/path/to/allowed/dir',
],
},
},
})
Note
server.fs.strictrestricts file access to the workspace root by default. Useserver.fs.allowto whitelist additional directories (e.g., monorepo siblings or symlinked packages).
Build Configuration
export default defineConfig({
build: {
outDir: 'dist', // output directory (default)
assetsInlineLimit: 4096, // inline assets < 4KB as base64
sourcemap: true, // generate source maps
cssCodeSplit: true, // CSS code splitting (default)
manifest: true, // generate manifest.json
emptyOutDir: true, // clear outDir before build
watch: null, // set to {} for watch mode
ssr: false, // SSR build mode
rollupOptions: {
// Rolldown options passthrough
input: 'index.html',
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
},
},
},
},
})
Library Mode
Build a reusable library instead of an application:
import { defineConfig } from 'vite'
import path from 'node:path'
export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'src/index.ts'),
name: 'MyLib',
fileName: 'my-lib',
},
rollupOptions: {
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
},
},
},
})
Preview Server Configuration
export default defineConfig({
preview: {
port: 4173,
headers: {
'Cache-Control': 'public, max-age=600',
},
},
})
CSS Configuration
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/variables" as *;`,
},
less: {
modifyVars: {
'primary-color': '#1DA57A',
},
javascriptEnabled: true,
},
},
},
})
JSON Handling
export default defineConfig({
json: {
namedExports: true, // allow named imports from .json (default)
stringify: 'auto', // stringify large JSON for performance (default)
},
})
TypeScript / JSX Transpilation
Vite v8 uses oxc by default for TypeScript and JSX transpilation. To use esbuild instead:
export default defineConfig({
oxc: false, // disable oxc, fall back to esbuild
esbuild: {
banner: '/* built with esbuild */',
footer: '/* end */',
},
})
Conditional Config
Export a function for environment-aware configuration:
export default defineConfig(({ command, mode }) => {
if (command === 'serve') {
return {
// dev-specific config
server: { port: 3000 },
}
} else {
return {
// build-specific config
build: { sourcemap: true },
}
}
})
Specifying a Config File
Override the default config file path:
vite --config my-config.js
Tip
For the complete configuration reference including all nested options and their defaults, see the Vite Admin Guide.
4. Core Usage
Dev Server
Start the development server:
vite
# or equivalently:
vite dev
vite serve
The dev server serves your project root as a web server with native ES module support. When you import a module in your source, the browser fetches it directly — no bundling step. This is what makes Vite's startup nearly instant regardless of application size.
Hot Module Replacement (HMR)
Vite provides out-of-the-box HMR for:
- Vue single-file components (via
@vitejs/plugin-vue) - React components (via
@vitejs/plugin-reactor@vitejs/plugin-react-swc) - Svelte components (via
@sveltejs/vite-plugin-svelte) - CSS / PostCSS / Sass / Less / Stylus — all CSS changes apply without full page reload
- JSX / TSX — with appropriate framework plugins
The HMR error overlay displays compile errors directly in the browser. Disable it with:
export default defineConfig({
server: {
hmr: {
overlay: false,
},
},
})
HMR API
For custom HMR handling in modules, use the import.meta.hot API:
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// handle the updated module
})
import.meta.hot.dispose(() => {
// cleanup side effects
})
}
import.meta.hot is undefined in production builds and tree-shaken away.
Forward Console
Vite v8 can forward console.log, console.warn, and console.error calls from the browser to your server terminal:
export default defineConfig({
server: {
forwardConsole: {
enabled: true,
},
},
})
This is useful for debugging without switching to browser DevTools.
Production Builds
Build your application for production:
vite build
Vite v8 uses Rolldown as the production bundler (replacing Rollup from earlier versions). Rolldown is a Rust-based bundler that provides significantly faster build times while maintaining Rollup plugin API compatibility.
The build produces optimized output in dist/ by default:
- JavaScript is minified and tree-shaken
- CSS is extracted, minified, and code-split
- Assets below
assetsInlineLimit(4KB default) are inlined as base64 - Assets above the limit are hashed and output to
dist/assets/
Watch Mode
Rebuild on file changes:
vite build --watch
Or configure in vite.config.js:
export default defineConfig({
build: {
watch: {},
},
})
Build Targets
Specify browser targets:
vite build --target es2022
Preview Server
After building, preview the production output locally:
vite preview
This starts a static file server serving dist/. It is not intended for production use — use a proper web server (nginx, Caddy, etc.) to serve your built files in production.
Dependency Pre-Bundling
Vite automatically pre-bundles dependencies from node_modules on first dev server start. This:
- Converts CommonJS and UMD packages to ESM
- Consolidates packages with many internal modules into a single request (e.g.,
lodash-eshas 600+ modules)
Pre-bundled dependencies are cached in node_modules/.vite/. Vite re-bundles when:
- Package manager lockfile changes (
package-lock.json,yarn.lock,pnpm-lock.yaml,bun.lockb) - Relevant fields in
vite.config.jschange - Patches in
patches/folder change
Force a re-bundle:
vite --force
Or:
vite optimize
Note
The
vite optimizecommand explicitly runs the dependency pre-bundling step. This is primarily useful for debugging — in normal development, Vite handles pre-bundling automatically.
5. Common Tasks
CSS Processing
Plain CSS
Import CSS directly in JavaScript modules:
import './style.css'
Vite handles @import inlining, URL rebasing, and PostCSS automatically (if a PostCSS config is present).
CSS Modules
Any file ending in .module.css is treated as a CSS Module:
/* button.module.css */
.button {
background: blue;
color: white;
}
.primary {
background: darkblue;
}
import styles from './button.module.css'
document.getElementById('btn').className = styles.button
// renders as: class="button_abc123"
Sass / SCSS
Install the preprocessor:
npm install -D sass
Use .scss or .sass files directly:
import './styles/app.scss'
Configure global variables or mixins:
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/variables" as *;`,
},
},
},
})
Less
npm install -D less
import './styles/app.less'
Stylus
npm install -D stylus
import './styles/app.styl'
LightningCSS
Vite supports LightningCSS as an alternative CSS transformer and minifier, providing significantly faster CSS processing.
CSS Code Splitting
In production builds, Vite automatically extracts CSS used by async chunks into separate files. They load in parallel with the chunk's JavaScript — no flash of unstyled content.
Disable CSS code splitting:
export default defineConfig({
build: {
cssCodeSplit: false, // bundle all CSS into one file
},
})
TypeScript
Vite supports TypeScript out of the box. In v8, oxc is the default transpiler (replacing esbuild from earlier versions).
Import .ts and .tsx files directly:
// main.ts
import { createApp } from './app'
createApp('#root')
Important
Vite performs transpilation only — it does not run type checking. Run
tsc --noEmitseparately (or usevue-tscfor Vue projects) to type-check your code during CI or as a parallel process.
JSX and TSX
JSX is supported in .jsx and .tsx files. Framework-specific JSX transforms require the corresponding plugin:
- React:
@vitejs/plugin-react - Vue:
@vitejs/plugin-vue-jsx - Preact:
@preact/preset-vite - Solid:
vite-plugin-solid
Static Assets
Import static assets to get their resolved URL:
import imgUrl from './image.png'
document.getElementById('hero').src = imgUrl
// In dev: /src/image.png
// In build: /assets/image-a1b2c3d4.png
Supported Asset Types
Vite recognizes these file extensions as static assets:
| Category | Extensions |
|---|---|
| Images | apng, bmp, png, jpg, jpeg, jfif, pjpeg, pjp, gif, svg, ico, webp, avif, cur, jxl |
| Media | mp4, webm, ogg, mp3, wav, flac, aac, opus, mov, m4a, vtt |
| Fonts | woff, woff2, eot, ttf, otf |
| Other | webmanifest, pdf, txt |
Add custom asset types:
export default defineConfig({
assetsInclude: ['**/*.gltf', '**/*.hdr'],
})
Asset Inline Limit
Assets smaller than assetsInlineLimit (default: 4096 bytes / 4KB) are inlined as base64 data URLs. Larger assets are emitted as files with content hashes.
export default defineConfig({
build: {
assetsInlineLimit: 8192, // 8KB
},
})
Import Suffixes
Vite supports special URL suffixes to control how assets are imported:
| Suffix | Effect | Example |
|---|---|---|
?raw |
Import as raw string | import shader from './frag.glsl?raw' |
?url |
Import as URL (skip inlining) | import iconUrl from './icon.svg?url' |
?inline |
Force inline as data URL | import img from './large.png?inline' |
?no-inline |
Force file emission (skip inline) | import tiny from './dot.png?no-inline' |
?worker |
Import as Web Worker | import Worker from './worker.js?worker' |
?worker&inline |
Inline Worker as base64 blob | import Worker from './worker.js?worker&inline' |
?worker&url |
Worker as URL | import workerUrl from './worker.js?worker&url' |
?sharedworker |
Import as SharedWorker | import SW from './sw.js?sharedworker' |
?sharedworker&inline |
Inline SharedWorker | import SW from './sw.js?sharedworker&inline' |
?sharedworker&url |
SharedWorker as URL | import swUrl from './sw.js?sharedworker&url' |
?url&inline |
URL with inline hint | import u from './file.txt?url&inline' |
?url&no-inline |
URL without inline | import u from './file.txt?url&no-inline' |
Raw Imports
Import file contents as a string:
import vertexShader from './shaders/vertex.glsl?raw'
import license from '../LICENSE?raw'
console.log(vertexShader)
// outputs the raw GLSL source
Web Workers
Import a script as a Web Worker:
import MyWorker from './worker.js?worker'
const worker = new MyWorker()
worker.postMessage({ cmd: 'start' })
worker.onmessage = (e) => {
console.log('Result:', e.data)
}
Inline the worker (useful when you cannot serve separate files):
import InlineWorker from './worker.js?worker&inline'
const worker = new InlineWorker()
SharedWorker usage:
import SharedWorker from './shared.js?sharedworker'
const shared = new SharedWorker()
WebAssembly
Import .wasm files with the ?init suffix:
import init from './processor.wasm?init'
const instance = await init()
const result = instance.exports.process(42)
Glob Import
Dynamically import multiple modules matching a glob pattern:
const modules = import.meta.glob('./modules/*.js')
// returns:
// {
// './modules/foo.js': () => import('./modules/foo.js'),
// './modules/bar.js': () => import('./modules/bar.js'),
// }
// Lazy-load a specific module:
const foo = await modules['./modules/foo.js']()
Eager loading (import all at once):
const modules = import.meta.glob('./modules/*.js', { eager: true })
// All modules are already imported
Named imports for tree-shaking:
const setups = import.meta.glob('./modules/*.js', {
import: 'setup',
})
// Each module's `setup` export is available as a lazy loader
Import as raw strings:
const templates = import.meta.glob('./templates/*.html', {
query: '?raw',
import: 'default',
})
Multiple patterns:
const modules = import.meta.glob([
'./components/**/*.vue',
'./pages/**/*.vue',
])
Negative patterns (exclusions):
const modules = import.meta.glob([
'./components/**/*.vue',
'!./components/internal/**',
])
Dynamic Import with Variables
Vite supports dynamic imports with template literal variables:
const page = 'home'
const module = await import(`./pages/${page}.js`)
Variables in dynamic imports are limited to one level of depth. Vite analyzes the possible matches at build time and generates code to load them.
Environment Variables
.env Files
Vite loads environment variables from .env files using dotenv and dotenv-expand:
| File | Purpose | Loaded when |
|---|---|---|
.env |
Base variables | Always |
.env.local |
Local overrides (gitignored) | Always |
.env.development |
Development variables | vite dev |
.env.production |
Production variables | vite build |
.env.development.local |
Local dev overrides | vite dev |
.env.production.local |
Local prod overrides | vite build |
Exposing Variables to Client Code
Only variables prefixed with VITE_ are exposed to client code:
# .env
DB_PASSWORD=secret # NOT exposed to client
VITE_API_URL=https://api.example.com # exposed
VITE_APP_TITLE=My App # exposed
Access in source:
console.log(import.meta.env.VITE_API_URL)
// → "https://api.example.com"
Warning
Never put secrets or credentials in
VITE_*variables. They are embedded verbatim in your client bundle and visible to anyone inspecting your JavaScript.
Built-In Environment Variables
| Variable | Type | Description |
|---|---|---|
import.meta.env.MODE |
string |
'development' or 'production' (or custom mode) |
import.meta.env.BASE_URL |
string |
The base config value |
import.meta.env.PROD |
boolean |
true in production |
import.meta.env.DEV |
boolean |
true in development |
import.meta.env.SSR |
boolean |
true in SSR mode |
Custom Modes
Use --mode to load a custom .env file:
vite build --mode staging
This loads .env.staging and .env.staging.local.
JSON Imports
Import JSON files with named exports:
import pkg from './package.json'
console.log(pkg.version)
// Named imports (tree-shakeable)
import { version, name } from './package.json'
console.log(version)
When json.namedExports is true (default), individual fields can be imported and unused fields are tree-shaken.
When json.stringify is 'auto' (default), large JSON files are serialized as strings for better performance.
HTML and Multi-Page Apps
Vite uses index.html as the entry point. For multi-page apps, create multiple HTML files and configure build inputs:
project/
├── index.html
├── about.html
├── contact/
│ └── index.html
└── src/
├── main.js
├── about.js
└── contact.js
import { defineConfig } from 'vite'
import path from 'node:path'
export default defineConfig({
build: {
rollupOptions: {
input: {
main: path.resolve(__dirname, 'index.html'),
about: path.resolve(__dirname, 'about.html'),
contact: path.resolve(__dirname, 'contact/index.html'),
},
},
},
})
In each HTML file, reference its module with <script type="module">:
<!-- about.html -->
<!DOCTYPE html>
<html>
<head><title>About</title></head>
<body>
<div id="app"></div>
<script type="module" src="/src/about.js"></script>
</body>
</html>
Server-Side Rendering (SSR)
Vite provides built-in SSR support. Create a server entry:
// src/entry-server.js
export function render(url) {
// render app to HTML string
return '<div id="app">...</div>'
}
Build the SSR bundle:
vite build --ssr src/entry-server.js
The SSR build outputs a CommonJS bundle suitable for server environments.
Module Runner
Vite v8 provides a Module Runner for SSR environments, allowing efficient server-side module execution with HMR support during development.
Source Maps
Enable source maps for production debugging:
vite build --sourcemap
Options:
export default defineConfig({
build: {
sourcemap: true, // generate .map files
// or: 'inline' // inline source maps
// or: 'hidden' // .map files without sourceMappingURL
},
})
Build Manifest
Generate a manifest file mapping original filenames to hashed output:
export default defineConfig({
build: {
manifest: true,
},
})
Produces dist/.vite/manifest.json:
{
"src/main.js": {
"file": "assets/main-BfH3kQ2f.js",
"src": "src/main.js",
"isEntry": true,
"css": ["assets/main-DiwrgTda.css"]
}
}
This is essential for server-rendered apps that need to reference the correct hashed filenames.
Public Directory
Files in public/ are served at the root path and copied to dist/ unchanged:
public/
├── favicon.ico
├── robots.txt
└── images/
└── og-image.png
Reference them with absolute paths (no import needed):
<link rel="icon" href="/favicon.ico" />
<img src="/images/og-image.png" />
Caution
Do not import files from
public/in JavaScript — they are not processed by Vite's module graph. Always use absolute URL paths like/filenameinstead.
6. Troubleshooting
Error: Cannot find module or Failed to resolve import
Cause: A dependency is missing or an import path is incorrect.
Solution:
- Run
npm installto ensure all dependencies are installed - Check for typos in the import path
- Verify
resolve.aliasmappings invite.config.js - Clear the dependency cache:
vite --force
Prevention: Use TypeScript or IDE extensions that validate import paths at edit time.
Error: Pre-transform error / [plugin:vite:import-analysis] Failed to resolve import
Cause: Vite cannot resolve an imported module during dev server operation.
Solution:
- Check that the package is listed in
dependenciesordevDependencies - For monorepo packages, ensure they are properly linked
- Try clearing pre-bundled dependencies:
rm -rf node_modules/.vite
npm run dev
Prevention: Keep package.json in sync with actual imports.
Error: Port already in use
Cause: Another process is using the default port (5173 for dev, 4173 for preview).
Solution:
vite --port 3000
Or use --strictPort to fail instead of auto-incrementing:
vite --strictPort --port 5173
Prevention: Configure a consistent port in vite.config.js.
HMR Not Working or Stops After Save
Cause: Several possibilities including circular dependencies, missing HMR boundary, or file system watcher issues.
Solution:
- Check the terminal for error messages
- For circular dependency issues (especially with TypeScript), refactor to break the cycle
- On WSL2 or networked drives, try polling mode by setting
server.watch.usePolling: true - Ensure your framework plugin is up to date
Prevention: Avoid circular imports. Keep framework plugins updated to match your Vite version.
Note
HMR may stop functioning after saving a TypeScript file that introduces a circular dependency. Vite detects these cycles but cannot always recover gracefully. Breaking the circular dependency resolves the issue.
CSS Ordering Differs Between Dev and Production
Cause: In development, CSS is loaded as individual modules via <style> tags. In production, CSS is extracted and combined, which can change cascade order.
Solution:
- Avoid relying on CSS import order for specificity conflicts
- Use more specific selectors or CSS Modules to isolate styles
- Explicitly control order with a single entry CSS file that
@imports in the correct sequence
Prevention: Use CSS Modules, scoped styles, or a CSS-in-JS solution to avoid cascade ordering issues.
vite build Produces Empty or Incorrect Output
Cause: Entry point misconfiguration or emptyOutDir clearing a non-default output path.
Solution:
- Verify
index.htmlexists at the project root (or configurebuild.rollupOptions.input) - Check that
build.outDiris correct - Ensure
<script type="module" src="...">in your HTML points to an existing file
Dependency Pre-Bundling Fails or Loops
Cause: A dependency has unusual packaging, or Vite cannot detect all dependencies upfront.
Solution:
- Force re-bundling:
vite --force - Manually include or exclude packages:
export default defineConfig({
optimizeDeps: {
include: ['problematic-package'],
exclude: ['package-with-its-own-esm'],
},
})
Error: [vite] Internal server error: Missing "./package.json" export in "some-package"
Cause: The dependency's exports field in package.json does not include ./package.json.
Solution: Add the package to optimizeDeps.include to force pre-bundling, which resolves the export map.
Build Fails with Unexpected token in a Dependency
Cause: A dependency contains syntax that the current transpiler cannot handle (e.g., newer ECMAScript features in a CJS package).
Solution:
- Add the package to
optimizeDeps.include - If using oxc and it fails, try disabling it for the affected file:
export default defineConfig({
optimizeDeps: {
include: ['legacy-package'],
},
})
Plugin Errors Are Hidden or Swallowed
Cause: Some plugin errors may not surface clearly in the console.
Solution:
- Run with debug logging:
vite --debug - Check if the plugin has a
configResolvedhook that might be silencing errors - Try removing plugins one by one to isolate the issue
- Update the plugin to its latest version
Legacy Browser Support
For projects that must support older browsers (IE11, older Safari), use the official legacy plugin:
npm install -D @vitejs/plugin-legacy
import legacy from '@vitejs/plugin-legacy'
export default defineConfig({
plugins: [
legacy({
targets: ['defaults', 'not IE 11'],
}),
],
})
Warning
@vitejs/plugin-legacyv8.0.1 may encounter issues with esbuild 0.27.7 or later. Pin your esbuild version if you experience build failures with this plugin.
7. FAQ
CLI Reference
vite / vite dev / vite serve
Start the development server.
vite [options]
| Flag | Description |
|---|---|
--host [host] |
Bind to specific host (0.0.0.0 for all interfaces) |
--port <port> |
Set port number |
--open [path] |
Open browser on start |
--cors |
Enable CORS |
--strictPort |
Fail if port is in use (instead of trying next) |
--force |
Force dependency re-bundling |
--config <file> |
Use specified config file |
--base <path> |
Public base path |
--logLevel <level> |
Log level: info, warn, error, silent |
--clearScreen |
Allow/disallow clearing the terminal screen |
--mode <mode> |
Set env mode (loads .env.<mode>) |
--debug [feat] |
Show debug logs (optionally for specific features) |
--filter <filter> |
Filter debug logs |
vite build
Build for production.
vite build [options]
| Flag | Description |
|---|---|
--outDir <dir> |
Output directory (default: dist) |
--assetsInlineLimit <n> |
Asset inline threshold in bytes (default: 4096) |
--ssr [entry] |
Build for SSR with given entry |
--sourcemap |
Generate source maps |
--minify [minifier] |
Enable/disable minification |
--manifest [name] |
Generate build manifest |
--ssrManifest [name] |
Generate SSR manifest |
--emptyOutDir |
Clear output directory before build |
--watch |
Rebuild on file changes |
--target <target> |
Transpilation target |
--config <file> |
Use specified config file |
--base <path> |
Public base path |
--logLevel <level> |
Log level |
--clearScreen |
Allow/disallow clearing the terminal screen |
--mode <mode> |
Set env mode |
vite preview
Preview the production build locally.
vite preview [options]
Accepts --host, --port, --strictPort, --open, --config, --base, --logLevel, --clearScreen, and --mode.
vite optimize
Run dependency pre-bundling explicitly.
vite optimize [options]
Accepts --force, --config, and --logLevel.
Q: What is the difference between Vite and traditional bundlers like webpack?
Traditional bundlers process your entire application upfront before serving anything. Vite takes a different approach: it serves source files directly via native ES modules during development, only transforming individual files on demand. The result is near-instant dev server startup regardless of project size. For production, Vite uses Rolldown to produce optimized bundles.
Q: Does Vite support CommonJS dependencies?
Yes. Vite's dependency pre-bundling step automatically converts CommonJS and UMD packages to ESM. This happens transparently during dev server startup. In rare cases involving conditional CJS modules, you may need to add the dependency to optimizeDeps.include.
Q: Can I use Vite without a framework?
Absolutely. The vanilla and vanilla-ts templates create a plain JavaScript/TypeScript project with no framework. Vite works as a general-purpose dev server and bundler for any web project.
Q: How do I deploy a Vite app?
Run vite build to produce a dist/ directory with static files. Deploy these to any static hosting provider: Netlify, Vercel, Cloudflare Pages, GitHub Pages, AWS S3 + CloudFront, or any web server capable of serving static files.
Q: How do I add HTTPS to the dev server?
Configure the server.https option with your certificate and key files in vite.config.js. For local development, tools like mkcert can generate trusted local certificates.
Q: What is import.meta.glob and when should I use it?
import.meta.glob is Vite's way of importing multiple modules matching a file pattern. Common use cases: auto-registering Vue components, loading all route modules, collecting markdown files for a blog. It replaces webpack's require.context.
Q: What changed in Vite v8 compared to earlier versions?
Key changes in v8:
- Rolldown replaces Rollup as the production bundler
- oxc replaces esbuild as the default TypeScript/JSX transpiler
- Node.js minimum version raised to
^20.19.0or>=22.12.0 - Module Preload Polyfill for legacy browsers
- Forward Console feature to pipe browser logs to the terminal
Q: How do I handle environment-specific configuration?
Use the --mode flag to load different .env files. Create .env.development, .env.production, .env.staging, etc. Variables with the VITE_ prefix are exposed to client code; all others remain server-side only.
Q: My vendor bundle is too large. How do I split it?
Use build.rollupOptions.output.manualChunks to control code splitting:
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
charts: ['d3', 'chart.js'],
},
},
},
},
})
Q: Can I use Vite for a library instead of an application?
Yes. Use build.lib to configure library mode. Vite will output ESM and UMD/CJS formats, externalize dependencies, and handle proper module exports. See the Library Mode section in this guide.
Q: How do I handle monorepo setups?
Vite works in monorepos. Use server.fs.allow to whitelist directories outside the project root. For linked packages, ensure they are properly listed in optimizeDeps.include if pre-bundling has trouble resolving them.
Q: Is there a way to analyze my bundle size?
Use rollup-plugin-visualizer (compatible with Vite via the plugin system):
npm install -D rollup-plugin-visualizer
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [visualizer({ open: true })],
})
This generates an interactive treemap of your bundle after building.