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

Thrown in configResolved when config.build.lib is truthy. plugin-legacy works by injecting <script> tags into HTML entry files and generating dual modern/legacy bundles tied to HTML entries. Library mode (build.lib) produces JS/CSS consumable by other bundlers, not HTML, so plugin-legacy's entire HTML-centric pipeline is incompatible. This is a hard, by-design limitation.

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 89620f09af)

Solutions

  1. Remove @vitejs/plugin-legacy from plugins when using build.lib; instead configure build.target to legacy browsers directly (e.g., build.target: 'es2015').
  2. If you need both a library build and a legacy app build, use separate vite configs or conditional plugin inclusion: `...(isLibBuild ? [] : [legacy()])`.
  3. For library consumers needing legacy support, have consumers add plugin-legacy in their own app build rather than in the library build.

Example fix

// before
plugins: [legacy()],
build: { lib: { entry: 'src/lib.ts', name: 'MyLib' } }
// after
plugins: [],
build: {
  lib: { entry: 'src/lib.ts', name: 'MyLib' },
  target: 'es2015' // transpile for older browsers directly
}
Defensive patterns

Strategy: validation

Validate before calling

// Check for library mode before adding the plugin
function getPlugins(config) {
  const plugins = []
  if (!config.build?.lib) {
    plugins.push(legacy())
  } else {
    console.warn('plugin-legacy skipped: library mode is not supported')
  }
  return plugins
}

Type guard

function isLibraryMode(config: UserConfig): boolean {
  return !!(config.build?.lib)
}

// usage
const plugins = isLibraryMode(config)
  ? []
  : [legacy()]

Try / catch

try {
  if (config.build?.lib) {
    throw new Error('Cannot use plugin-legacy with build.lib')
  }
} catch (e) {
  console.warn(e.message, '— omitting plugin-legacy')
}

Prevention

When it happens

Trigger: Configuring build.lib in vite.config (e.g., { build: { lib: { entry: 'src/lib.ts', formats: ['es'] } } }) while simultaneously including the legacy plugin in the plugins array.

Common situations: A developer building a component library or SDK wants to support legacy browsers and adds @vitejs/plugin-legacy, not realizing it only works for app builds (HTML entries). Common when migrating an app to a library build without removing the plugin.

Related errors


AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03). Data as JSON: /data/errors/134b22b3698f1efd.json. Report an issue: GitHub.