vitejs/vite · error · Error
Failed to resolve ${JSON.stringify(id)}. This package is ESM
Error message
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. What it means
Thrown during Vite's config-file bundling when a dependency is resolved as a CommonJS `require` but the package only ships ESM. The resolver first attempts `nodeResolveWithVite` with `isRequire: true`; on failure it retries without that flag, and if the import-style resolve succeeds it concludes the package is ESM-only and rejects the require. It points to the official troubleshooting guide because mixing CJS config files with ESM-only deps is a well-known interop failure.
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 89620f09af)
Solutions
- Rename the config to `vite.config.mjs` (or add `"type": "module"` to package.json) so it is treated as ESM and uses `import` instead of `require`.
- Replace any `require('pkg')` calls in the config with dynamic `import()` or static `import`.
- Downgrade the offending dependency to a version that still ships a CJS build, or find a CJS-compatible alternative.
- If you must keep CJS, pre-bundle the dep yourself or import it via a wrapper that re-exports from an ESM entry.
Example fix
// before (vite.config.cjs)
const { defineConfig } = require('vite')
const execa = require('execa') // execa v6+ is ESM-only
// after (rename to vite.config.mjs)
import { defineConfig } from 'vite'
import { execa } from 'execa' Defensive patterns
Strategy: validation
Validate before calling
// Before writing a CJS config that requires a dep, verify it ships CJS:
const pkg = require.resolve('<dep>/package.json')
const meta = require(pkg)
const hasCjs = meta.main || (meta.exports && JSON.stringify(meta.exports).includes('require'))
if (!hasCjs && (meta.type === 'module' || meta.exports?.import)) {
throw new Error('<dep> is ESM-only; convert this config to ESM (.mjs)')
} Type guard
// Narrow a config format to whether require() is safe
function isCjsSafeConfig(configPath: string): boolean {
return /\.c?js$/.test(configPath) && !fs.existsSync(path.join(process.cwd(), 'package.json'))
? false
: require('./package.json').type !== 'module'
} Prevention
- Default new projects to ESM: set "type": "module" and use vite.config.mjs.
- Never require() in a Vite config — use static/dynamic import.
- When upgrading a dep, check its changelog for an ESM-only major bump.
When it happens
Trigger: A `vite.config.cjs` (or a project without `"type": "module"`) that `require()`s an ESM-only package, or any config whose bundled graph contains a `require(...)` of an ESM-only dep. The resolveId hook in config.ts:2577 runs with `isImport=false`, fails, then the retry at config.ts:2580 succeeds, triggering the throw at config.ts:2585.
Common situations: Using a newer ESM-only release of a library (e.g. `execa`, `got`, `node-fetch` v3+, `chalk` v5+) inside a legacy `.cjs` config; monorepo root lacking `"type": "module"`; scaffolding tools that emit CJS configs by default; upgrading a dependency whose major version moved to ESM-only.
Related errors
- import.meta.resolve is not supported in CJS config files
- { runtime: "${result.runtime}" } is not supported for assets
- `renderLegacyChunks` and `renderModernChunks` cannot be both
- @vitejs/plugin-legacy does not support library mode.
- HMR is not supported by this runner transport, but `hmr` opt
AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03).
Data as JSON: /data/errors/577c1b6686ebb7c3.json.
Report an issue: GitHub.