vitejs/vite · error · Error
Failed to resolve ${id}. This package is ESM only but it was
Error message
Failed to resolve ${id}. This package is ESM only but it was tried to load by `require`. See https://vite.dev/guide/troubleshooting.html#this-package-is-esm-only for more details. What it means
During config bundling Vite resolves import specifiers with nodeResolveWithVite. When a specifier resolves as ESM-only (require fails) but works as a static import, Vite throws a targeted error pointing at the troubleshooting guide. This typically means an ESM-only package is being pulled into a CJS context, or a CJS-resolver path was forced.
Source
Thrown at packages/vite/src/node/config.ts:2585
}
const isImport = isESM || kind === 'dynamic-import'
let idFsPath: string | undefined
try {
idFsPath = nodeResolveWithVite(id, importer, {
root,
isRequire: !isImport,
})
} catch (e) {
if (!isImport) {
let canResolveWithImport = false
try {
canResolveWithImport = !!nodeResolveWithVite(id, importer, {
root,
})
} catch {}
if (canResolveWithImport) {
throw new Error(
`Failed to resolve ${JSON.stringify(
id,
)}. This package is ESM only but it was tried to load by \`require\`. See https://vite.dev/guide/troubleshooting.html#this-package-is-esm-only for more details.`,
)
}
}
throw e
}
if (!idFsPath) return
// always no-externalize json files as rolldown does not support import attributes
if (idFsPath.endsWith('.json')) {
return idFsPath
}
if (idFsPath && isImport) {
idFsPath = pathToFileURL(idFsPath).href
}
return { id: idFsPath, external: true }View on GitHub (pinned to b4d66fee14)
Solutions
- Rename your config to vite.config.mjs (or set package.json type: module) so it is loaded as ESM.
- Downgrade or replace the ESM-only package with a CJS-compatible version.
- Bundle the dependency into the config (configLoader: 'bundle') rather than requiring it at runtime.
Example fix
// before: vite.config.js (CommonJS) requires an ESM-only package
const pkg = require('esm-only-pkg')
// after: rename to vite.config.mjs and import
import pkg from 'esm-only-pkg' Defensive patterns
Strategy: validation
Validate before calling
function loadConfigAsEsm(specifier) {
try { return require.resolve(specifier); }
catch (e) {
if (/^Error\(ERR_REQUIRE_ESM\)/.test(String(e.message)) || e.code === 'ERR_REQUIRE_ESM') {
throw new Error(`${specifier} is ESM-only; load the config as ESM (vite.config.mjs)`);
}
throw e;
}
} Type guard
function looksEsmOnly(pkg) {
return Boolean(pkg && pkg.type === 'module' && !pkg.main);
} Prevention
- Use vite.config.mjs when depending on ESM-only packages.
- Set package.json type: module for ESM projects.
When it happens
Trigger: An ESM-only dependency (no CJS entry) is required via require() in a config or plugin loaded in CJS mode; or the resolver falls back to the require path and the package lacks main/require fields.
Common situations: Mixing ESM-only packages (e.g. 'chalk', 'execa' v6+) into a CommonJS vite.config.js; older Node versions whose default resolution prefers require; packages whose package.json lacks a valid exports map.
Related errors
- config must export or return an object.
- import.meta.resolve is not supported in CJS config files
- Package subpath '${relativeId}' is not defined by "exports"
- [vite] Named export '${lastBinding}' not found. The requeste
- When "build.cssCodeSplit: false" is set, "rolldownOptions.in
AI-assisted analysis of vitejs/vite@b4d66fee14 (2026-08-11).
Data as JSON: /api/errors/a69aba04e06fe318.
Report an issue: GitHub.