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

  1. Remove `legacy()` from the plugins array for any build that uses `build.lib`.
  2. Split your config: use a function/config that adds `legacy()` only when building the app (HTML) target, and omits it for the library target.
  3. 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

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


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)