vitejs/vite · error · Error
@vitejs/plugin-legacy does not support library mode.
Error message
@vitejs/plugin-legacy does not support library mode.
What it means
plugin-legacy's design is built around HTML entry points: it injects `<script nomodule>`/SystemJS tags and polyfill chunks via `transformIndexHtml`, splitting a build into modern + legacy bundles. Library mode (`build.lib`) has no HTML entry and produces a single consumable package, so the legacy HTML injection pipeline does not apply. The plugin hard-rejects library mode in `configResolved` of the `vite:legacy-post-process` plugin.
Solutions
- Remove `legacy()` from the plugins array for any build that uses `build.lib`.
- Split your config: use a function/config that adds `legacy()` only when building the app (HTML) target, and omits it for the library target.
- Use an environment variable or mode check to conditionally include the legacy plugin: `plugins: [...(isLib ? [] : [legacy()])]`.
Example fix
// before
export default defineConfig({
build: { lib: { entry: 'src/index.ts' } },
plugins: [legacy()],
})
// after
export default defineConfig(({ mode }) => ({
build: { lib: { entry: 'src/index.ts' } },
plugins: [/* legacy() removed - not supported in lib mode */],
})) Defensive patterns
Strategy: validation
Validate before calling
import type { InlineConfig } from 'vite'
function assertNoLegacyInLibMode(cfg: InlineConfig) {
const hasLib = !!(cfg.build && (cfg.build as any).lib)
const hasLegacy = (cfg.plugins || []).flat().some((p: any) => p && p.name && /legacy/i.test(p.name))
if (hasLib && hasLegacy) {
throw new Error('@vitejs/plugin-legacy cannot be used with build.lib - remove the plugin for lib builds')
}
} Type guard
function isAppBuild(cfg: { build?: { lib?: unknown } }): boolean {
return !cfg?.build?.lib
} Prevention
- Keep separate configs for app vs library builds.
- Conditionally add legacy(): plugins: [...(mode === 'lib' ? [] : [legacy()])].
When it happens
Trigger: Having both `build.lib` set in vite.config AND `@vitejs/plugin-legacy` present in `plugins`, then running `vite build`. The throw fires during config resolution before any bundling starts.
Common situations: Reusing a single vite.config that was authored for an app (with `legacy()`) to also build a library entry. Adding `legacy()` to a monorepo package config that is in library mode. Forgetting that a shared config sets `build.lib`.
Related errors
- Either "build.lib.entry" or the top-level "input" option is…
- `renderLegacyChunks` and `renderModernChunks` cannot be…
- Name in package.json is required if option…
- No corresponding legacy entry chunk found for
- No corresponding legacy polyfill chunk found for
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/134b22b3698f1efd.
Report an issue: GitHub.
Appendix: source
Thrown at packages/plugin-legacy/src/index.ts:462
'es2015',
)
}
},
}
const legacyPostPlugin: Plugin = {
name: 'vite:legacy-post-process',
enforce: 'post',
apply: 'build',
renderStart(opts) {
// Empty the nested map for this output
outputToChunkFileNameToPolyfills.set(opts, null)
},
configResolved(_config) {
if (_config.build.lib) {
throw new Error('@vitejs/plugin-legacy does not support library mode.')
}
config = _config
const viteVersion = this.meta.viteVersion
supportsLegacyOxcMinification =
!!viteVersion &&
isVersionGte(viteVersion, legacyOxcMinificationSupportedVersion)
if (!supportsLegacyOxcMinification && config.build.minify === 'oxc') {
config.logger.warn(
colors.yellow(
`'oxc' minifier is not supported for legacy chunks by Vite version ${viteVersion}. ` +
`Please upgrade to Vite version ${legacyOxcMinificationSupportedVersion} or later.`,
),
)
}
if (isDebug) {View on GitHub (pinned to b4d66fee14)