vitejs/vite · error · Error
terser not found. Since Vite v3, terser has become an option
Error message
terser not found. Since Vite v3, terser has become an optional dependency. You need to install it.
What it means
Since Vite v3 terser is an optional peer dependency and is loaded lazily by the terser plugin at packages/vite/src/node/plugins/terser.ts:33. If build.minify === 'terser' (or @vitejs/plugin-legacy needs it) and neither the user's project root nor Vite's own install directory can resolve 'terser', loadTerserPath throws. esbuild (the default) does not need terser.
Source
Thrown at packages/vite/src/node/plugins/terser.ts:33
* when minifying files with terser.
*
* @default number of CPUs minus 1
*/
maxWorkers?: number
}
let terserPath: string | undefined
function loadTerserPath(root: string) {
if (terserPath) return terserPath
// Try resolve from project root first, then the current vite installation path
const resolved =
nodeResolveWithVite('terser', undefined, { root }) ??
nodeResolveWithVite('terser', _dirname, { root })
if (resolved) return (terserPath = resolved)
// Error if we can't find the package
throw new Error(
'terser not found. Since Vite v3, terser has become an optional dependency. You need to install it.',
)
}
export function terserPlugin(config: ResolvedConfig): Plugin {
const { maxWorkers, ...terserOptions } = config.build.terserOptions
const makeWorker = () =>
new WorkerWithFallback(
() =>
async (
terserPath: string,
code: string,
options: TerserMinifyOptions,
) => {
const terser: typeof import('terser') = await import(terserPath)
try {
return (await terser.minify(code, options)) as TerserMinifyOutputView on GitHub (pinned to 89620f09af)
Solutions
- Run `npm i -D terser` (or pnpm/yarn add -D terser) in the project root so nodeResolveWithVite finds it.
- If you did not intend to use terser, set build.minify: 'esbuild' (the default) and remove any terserOptions config.
- For CI with optional deps stripped, install with --include=optional or add terser as a direct devDependency so it is never pruned.
- In a monorepo, ensure terser is installed in the same workspace that runs the build, or set Vite's resolve to look in the workspace root.
Example fix
// before
export default defineConfig({ build: { minify: 'terser' } })
// after (option A: keep terser)
// npm i -D terser
// after (option B: drop terser)
export default defineConfig({ build: { minify: 'esbuild' } }) Defensive patterns
Strategy: validation
Validate before calling
import { createRequire } from 'node:module'
function terserAvailable(): boolean {
try { createRequire(process.cwd() + '/package.json').resolve('terser'); return true }
catch { return false }
}
if (config.build?.minify === 'terser' && !terserAvailable()) {
throw new Error('terser minify requested but terser is not installed; run `npm i -D terser`')
} Type guard
function hasTerser(cwd = process.cwd()): boolean {
try { createRequire(cwd + '/package.json').resolve('terser'); return true }
catch { return false }
} Prevention
- Add terser to devDependencies whenever build.minify is 'terser' or @vitejs/plugin-legacy is used.
- In CI install without stripping optional deps, or pin terser as a direct devDependency.
- Default to minify: 'esbuild' unless you specifically need terser.
When it happens
Trigger: Setting build.minify: 'terser' in vite.config; using @vitejs/plugin-legacy which forces the terser plugin via applyToEnvironment; running a build in a fresh install where terser was pruned as an optional dep; a corrupted node_modules where terser's package.json exists but its main file is missing.
Common situations: Copying a vite.config from a v2 project (terser was the default then) into a v3+ project without adding terser; CI caching node_modules with --omit=optional discarding terser; monorepo hoisting leaving terser only in a sibling workspace so it resolves from project root but not from Vite's install dir.
Related errors
- [vite]: Rolldown failed to resolve import "${exporter}" from
- No environment found
- Either "build.lib.entry" or the top-level "input" option is
- rolldownOptions.input should not be an html file when buildi
- When "build.cssCodeSplit: false" is set, "rolldownOptions.in
AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03).
Data as JSON: /data/errors/8cfdfe3e462d549b.json.
Report an issue: GitHub.