server.portnumberDefault: 5173The port the dev server listens on. If the port is already in use, Vite will automatically try the next available port unless `server.strictPort` is set to `true`.
server: {
port: 3000,
}Vite config cheat sheet — 60+ vite.config.ts options with defaults, examples, and pitfalls.
server.portnumberDefault: 5173The port the dev server listens on. If the port is already in use, Vite will automatically try the next available port unless `server.strictPort` is set to `true`.
server: {
port: 3000,
}server.hoststring | booleanDefault: 'localhost'Set to `"0.0.0.0"` or `true` to expose the dev server on all network interfaces, including LAN and public addresses. Required when testing on a mobile device on the same network.
Exposing the dev server on all interfaces can be a security risk on public networks. Use with caution and only on trusted networks.
server: {
host: true, // same as '0.0.0.0'
}server.openboolean | stringDefault: falseAutomatically open the app in the browser when the server starts. Pass a URL string to open a specific page, e.g. `"/dashboard"` to skip the homepage.
server: {
open: true,
// or: open: '/dashboard',
}server.proxyRecord<string, string | ProxyOptions>Default: undefinedConfigure custom proxy rules for the dev server. Requests matching the key pattern are forwarded to the target. Use `changeOrigin: true` when the target is on a different hostname. Use `rewrite` to strip a path prefix the backend does not expect.
Forgetting `changeOrigin: true` when the proxy target is on a different hostname causes the backend to reject requests because the `Host` header does not match.
server: {
proxy: {
'/api': {
target: 'http://localhost:3001',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
'/ws': {
target: 'ws://localhost:3001',
ws: true,
},
},
}server.corsboolean | CorsOptionsDefault: true (for *.localhost and 127.0.0.1)Configure CORS for the dev server. Set to `true` to allow all origins, or pass a `CorsOptions` object for fine-grained control. Useful when testing your dev server from a different origin.
server: {
cors: true,
// or fine-grained:
// cors: {
// origin: 'https://example.com',
// methods: ['GET', 'POST'],
// },
}server.hmrboolean | HmrOptionsDefault: trueEnable or disable HMR (Hot Module Replacement). Set `hmr: false` to disable. Pass an object to configure the HMR WebSocket connection — useful when running Vite behind a reverse proxy that does not forward WebSocket connections correctly.
When running Vite behind a reverse proxy (nginx, Caddy), HMR WebSocket connections often fail because the proxy is not configured to forward WebSocket upgrades. Add the HMR overlay host explicitly to fix it.
server: {
hmr: {
protocol: 'ws',
host: 'localhost',
port: 5173,
},
}server.headersOutgoingHttpHeadersDefault: undefinedSpecify custom HTTP response headers for the dev server. Use to add security headers like `Cross-Origin-Opener-Policy` or to enable `SharedArrayBuffer` which requires `Cross-Origin-Embedder-Policy: require-corp`.
server: {
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
},
}server.strictPortbooleanDefault: falseWhen set to `true`, Vite exits with an error if the configured port is already in use instead of silently trying the next port. Useful in CI environments or scripts that depend on a specific port.
server: {
port: 3000,
strictPort: true,
}preview.portnumberDefault: 4173The port used by `vite preview`, which serves the production build locally. Separate from `server.port` to avoid conflicts when running both simultaneously.
preview: {
port: 8080,
open: true,
}build.targetstring | string[]Default: 'modules'The browser compatibility target for the production build. `"modules"` targets browsers with native ES module support (Chrome 87+, Firefox 78+, Safari 14+). Use `"esnext"` for the latest syntax. Pass an array like `["chrome87", "firefox78", "safari14"]` to target a specific browser set. Uses esbuild transforms for syntax lowering.
Setting `target: "esnext"` does no syntax downleveling — it assumes the browser supports all latest JS features. Use a specific year (e.g. "es2020") for production apps targeting older browsers.
build: {
target: 'es2020',
// or: target: ['chrome87', 'firefox78', 'safari14'],
}build.outDirstringDefault: 'dist'The output directory for the production build, relative to the project root. Vite will empty this directory before building if `build.emptyOutDir` is `true`.
build: {
outDir: 'dist',
}build.assetsDirstringDefault: 'assets'Subdirectory inside `outDir` where generated assets (JS chunks, CSS, images) are placed. The full path of a chunk is `{outDir}/{assetsDir}/[name]-[hash].js`.
build: {
assetsDir: 'static', // outputs to dist/static/
}build.emptyOutDirbooleanDefault: true if outDir is inside rootClears the output directory before building. Defaults to `true` when `outDir` is inside the project root, `false` when it is outside (to prevent accidental deletion). Set explicitly to `true` to always clean.
build: {
emptyOutDir: true,
}build.minifyboolean | 'terser' | 'esbuild'Default: 'esbuild'Controls JS minification. `"esbuild"` is the default and is very fast. `"terser"` produces slightly smaller output but is 20-40× slower. Set to `false` to disable minification entirely — useful for debugging production builds.
build: {
minify: 'esbuild', // fast (default)
// minify: 'terser', // smaller, slower
// minify: false, // disable for debugging
}build.sourcemapboolean | 'inline' | 'hidden'Default: falseGenerate source maps for the production build. `true` creates separate `.map` files. `"inline"` embeds the source map as a data URI in the bundle. `"hidden"` creates `.map` files without the `//# sourceMappingURL` comment — use with error monitoring tools that upload maps privately.
build: {
sourcemap: true,
// or 'inline' | 'hidden'
}build.rollupOptionsRollupOptionsDefault: {}Directly customize the Rollup bundle configuration. Commonly used to configure `external` dependencies for libraries, `output.manualChunks` for code splitting, and `input` for multi-page apps. Full Rollup API is available.
build: {
rollupOptions: {
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM',
},
manualChunks: {
vendor: ['lodash', 'axios'],
},
},
},
}build.libLibraryOptionsDefault: undefinedConfigure Vite in library mode for publishing npm packages. Specify the entry point and output formats. Always set `rollupOptions.external` to list peer dependencies that should not be bundled.
build: {
lib: {
entry: 'src/index.ts',
name: 'MyLib',
fileName: 'my-lib',
formats: ['es', 'cjs'],
},
rollupOptions: {
external: ['react', 'react-dom'],
},
}build.cssCodeSplitbooleanDefault: trueWhen enabled (default), CSS imported by async JS chunks is split into separate CSS files. When disabled, all CSS is combined into a single file. Set to `false` when building a library to keep CSS in JS, or when you want a single CSS bundle.
build: {
cssCodeSplit: true, // default, split per chunk
// cssCodeSplit: false, // one CSS file
}build.assetsInlineLimitnumberDefault: 4096 (4 KB)Assets smaller than this threshold (in bytes) are inlined as base64 data URIs instead of being emitted as separate files. Reduces HTTP requests for small assets at the cost of larger JS/CSS bundle size. Set to `0` to disable inlining.
build: {
assetsInlineLimit: 8192, // 8 KB
// assetsInlineLimit: 0, // never inline
}build.chunkSizeWarningLimitnumberDefault: 500 (kB)Chunk size warning threshold in kB. Vite warns when a chunk exceeds this size. Increase the limit only if you have verified that large chunks are acceptable; better to use `rollupOptions.output.manualChunks` to split them.
Raising this limit to suppress warnings is not a fix — large chunks harm page load performance. Investigate with `npx vite-bundle-visualizer` and split the offending chunks using `manualChunks`.
build: {
chunkSizeWarningLimit: 1000, // 1 MB
}build.copyPublicDirbooleanDefault: trueWhen `true`, files in the `public/` directory are copied to `outDir` at the end of the build. Set to `false` when building a library — libraries do not need the public directory contents.
build: {
copyPublicDir: false, // useful for library builds
}resolve.aliasRecord<string, string> | Alias[]Default: {}Define file system path aliases. Any import matching a key is replaced with the corresponding path value at build time. The most common use is creating a `@/` alias for the `src/` directory. Remember to add matching `paths` in `tsconfig.json` — Vite and TypeScript alias configs are independent.
Setting `resolve.alias` in Vite but not in `tsconfig.json` paths causes TypeScript to report "Cannot find module" on every aliased import even though Vite resolves files correctly.
import path from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@utils': path.resolve(__dirname, './src/utils'),
},
},
});resolve.extensionsstring[]Default: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json']File extensions tried when resolving bare imports without an extension. The default list covers the common TypeScript and JavaScript extensions. Avoid adding `.vue`, `.svelte`, etc. here — framework plugins handle those.
resolve: {
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'],
}resolve.conditionsstring[]Default: ['module', 'browser', 'development|production']Conditions checked against the `exports` field in `package.json`. Vite uses `"browser"` in the client build and `"node"` in SSR. Add custom conditions to resolve package entry points differently per environment.
resolve: {
conditions: ['module', 'browser'],
}resolve.dedupestring[]Default: []Force specific packages to resolve to the same instance. Prevents duplicate instances in the module graph, which can cause issues with singletons (React context, Vue reactivity system). Useful when using local packages via `file:` links or monorepos.
The most common symptom of a missing `dedupe` entry is: React hooks throwing "Invalid hook call" or Vue components losing reactivity — caused by two copies of React/Vue being loaded.
resolve: {
dedupe: ['react', 'react-dom'],
}plugins(Plugin | Plugin[])[]Default: []Array of Vite plugins. Plugins are applied in order. Framework plugins (e.g. `@vitejs/plugin-react`) should generally come first. You can return `null` or `false` inside the array to conditionally skip a plugin.
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
react(),
],
});plugins (conditional)Plugin | false | nullDefault: n/aLoad a plugin only in specific modes by using a ternary or logical AND inside the plugins array. `false` and `null` values are filtered out by Vite. The `command` and `mode` parameters from `defineConfig` let you enable plugins only for builds or only in production.
export default defineConfig(({ command, mode }) => ({
plugins: [
react(),
mode === 'production' && vitePWA(), // only in prod
command === 'build' && bundleAnalyzer(),
].filter(Boolean),
}));defineConfigUserConfig | ConfigEnv => UserConfigDefault: n/aHelper function that provides TypeScript autocomplete for the config object. Pass a function to receive `command` (`"serve"` | `"build"`), `mode` (e.g. `"development"` | `"production"`), and `isSsrBuild` — useful for environment-aware configuration.
import { defineConfig } from 'vite';
export default defineConfig(({ command, mode }) => {
return {
build: {
sourcemap: command === 'serve', // sourcemap in dev only
},
};
});defineRecord<string, any>Default: {}Define global constant replacements. Values are replaced as-is in the source code (not quoted). `import.meta.env.VITE_*` should be preferred for runtime env vars, but `define` is useful for build-time constants like feature flags and version strings.
String values must be wrapped in `JSON.stringify()`. Writing `__VERSION__: "1.0"` inserts the literal `1.0` identifier into source — use `__VERSION__: JSON.stringify("1.0")` instead.
define: {
__APP_VERSION__: JSON.stringify('1.2.3'),
__FEATURE_FLAG__: true,
}basestringDefault: '/'The public base path when served in development or production. Must include a trailing slash. Set to `"/sub-path/"` when deploying to a sub-directory (GitHub Pages, Netlify sub-paths). All asset URLs will be prefixed with this value.
Missing a trailing slash (e.g. `base: "/my-app"` instead of `"/my-app/"`) causes incorrect asset URL generation in some cases. Always include the trailing slash.
export default defineConfig({
base: '/my-app/', // deployed to example.com/my-app/
});css.modulesCSSModulesOptionsDefault: {}Configure CSS Modules behavior. `localsConvention: "camelCaseOnly"` converts dashed class names to camelCase in JS. `generateScopedName` lets you customize the scoped class name format — useful for readable class names in development.
css: {
modules: {
localsConvention: 'camelCaseOnly',
generateScopedName: '[name]__[local]__[hash:5]',
},
}css.preprocessorOptionsRecord<string, object>Default: {}Pass options to CSS preprocessors (Sass, Less, Stylus). The most common use is injecting global variables or imports so they are available in every style file without explicit imports.
css: {
preprocessorOptions: {
scss: {
additionalData: '@use "@/styles/variables" as *;',
},
less: {
globalVars: {
primaryColor: '#1890ff',
},
},
},
}css.postcssstring | PostCSSConfigDefault: auto-discovered postcss.config.jsInline PostCSS configuration or a path to a PostCSS config file. Use to configure plugins like `autoprefixer` and `cssnano`. When specified here, Vite does not search for an external `postcss.config.js` file.
import autoprefixer from 'autoprefixer';
css: {
postcss: {
plugins: [
autoprefixer(),
],
},
}css.devSourcemapbooleanDefault: falseEnable CSS source maps in development. When enabled, browser DevTools shows the original CSS file location instead of the transformed output. Has a slight performance cost — leave disabled unless you are actively debugging CSS.
css: {
devSourcemap: true,
}optimizeDeps.includestring[]Default: []Force-include specific dependencies in the pre-bundling step. Useful for dependencies that are not automatically detected (e.g. deeply nested imports, dynamic imports). Entries must be resolvable import paths, not file system paths.
optimizeDeps: {
include: ['lodash-es', 'some-cjs-dep > nested-dep'],
}optimizeDeps.excludestring[]Default: []Exclude specific dependencies from pre-bundling. Use for ESM-native packages that have circular dependencies or ship broken CJS builds that esbuild handles incorrectly. Also useful for large packages where you only use a small part.
optimizeDeps: {
exclude: ['@ffmpeg/ffmpeg', 'some-esm-native-dep'],
}optimizeDeps.forcebooleanDefault: falseForce re-run of dependency pre-bundling, ignoring the cached result. Use this temporarily when the cache seems stale. Do not commit this to `vite.config.ts` — it slows down dev startup for everyone. Use the CLI flag `vite --force` for a one-time reset instead.
Committing `optimizeDeps.force: true` to the repo makes cold dev starts slow for every team member. Use `vite --force` on the command line for a one-off re-bundle.
optimizeDeps: {
force: true, // ⚠ temporary only, don't commit
}esbuildEsbuildOptions | falseDefault: {}Options passed to esbuild for individual file transforms. `esbuild.jsxInject` auto-imports React so you do not need `import React from "react"` in every file. `esbuild.drop` removes `console` or `debugger` calls in production. Set to `false` to disable esbuild transforms entirely.
esbuild: {
jsxInject: `import React from 'react'`,
drop: ['console', 'debugger'], // prod only
target: 'es2020',
}ssr.noExternalstring | RegExp | (string | RegExp)[] | trueDefault: []Force specified dependencies to be bundled into the SSR output instead of being externalized. Useful for packages that do not ship a valid CJS build or use browser-specific globals that need to be transformed.
ssr: {
noExternal: ['some-esm-only-package', /^@my-org//],
}Searchable reference for every important vite.config.ts option, covering six categories you reach for on every project. Server & Preview: server.port, server.host, server.open, server.proxy (with rewrite rules), server.https, server.hmr, server.cors, server.headers, preview.port. Build: build.target, build.outDir, build.assetsDir, build.emptyOutDir, build.minify, build.sourcemap, build.rollupOptions, build.lib, build.cssCodeSplit, build.assetsInlineLimit, build.chunkSizeWarningLimit, build.reportCompressedSize, build.copyPublicDir. Resolve: resolve.alias, resolve.extensions, resolve.conditions, resolve.dedupe. Plugins: plugins array, ordering, framework plugins (React, Vue, Svelte), conditional plugin loading, defineConfig helper with mode/env awareness. CSS: css.modules, css.preprocessorOptions (Sass variables, Less globalVars), css.postcss, css.devSourcemap. Optimizaton: optimizeDeps.include, optimizeDeps.exclude, optimizeDeps.force, ssr.noExternal, esbuild options. Every entry shows the type, default value, bilingual EN/ZH description, a copy-ready vite.config.ts snippet, and a pitfall note where relevant. Search filters across option name, description, snippet, and pitfall. Category chips scope to any single group. 100% client-side, works offline.
Paste or drop your content into the tool panel.
Click the button. All processing is local in your browser.
Copy the result or download to disk in one click.
Use it in the small gaps between coding, reviewing, debugging, and shipping.
These links move the current task into a more complete workflow.
Your React app calls `/api/users` in development, but the Express backend runs on port 3001. You find `server.proxy` in the cheatsheet, copy the snippet with `changeOrigin: true` and `rewrite`, and both servers talk to each other without CORS errors — in under two minutes.
Your codebase has `import Button from '../../../components/Button'` everywhere. You look up `resolve.alias`, copy the snippet, update your tsconfig paths to match, and all your imports become clean `@/components/Button` in one pass.
Your Vite dev server takes 15 seconds to start because it re-bundles a large CommonJS library on every cold start. You find `optimizeDeps.include`, add the offending package, and startup drops to 2 seconds because Vite caches the pre-bundled result.
You want to publish a React component library as an npm package with both ESM and CJS outputs. The cheatsheet shows `build.lib` with `formats: ['es', 'cjs']`, `rollupOptions.external` for peer dependencies (React, ReactDOM), and `build.sourcemap: true` for debuggable published code.
Forgetting `changeOrigin: true` in server.proxy when the target is a different hostname — the backend rejects the request because the Host header does not match.
Setting `resolve.alias` in Vite but not in tsconfig.json paths — Vite resolves files correctly but TypeScript reports "Cannot find module" on every aliased import.
Using `optimizeDeps.force: true` in committed config — it forces a full re-bundle on every `vite dev` startup, making cold starts slow for everyone on the team.
Folks in your role tend to reach for these alongside this tool.