How to fix Error [ERR_REQUIRE_ESM]: require() of ES Module not supported in React
A React build or runtime throws "require() of ES modules is not supported" when CommonJS code tries to load an ES module (for example node-fetch v3 or strip-ansi v7) because Node enforces module system compatibility and CRA/Next builds still emit require().
Quick fix
Fixes ERR_REQUIRE_ESM
// fetch-wrapper.cjs
const fetch = (...args) =>
import('node-fetch').then(({ default: fetch }) => fetch(...args));
module.exports = { fetch };
// usage
const { fetch } = require('./fetch-wrapper.cjs');
fetch(url).then((result) => result.json());- Load the ESM-only package with dynamic import()
- Convert React tooling to ESM (package.json "type": "module")
- Pin the last CommonJS-friendly version of the dependency
- Ensure configuration files stay CommonJS with .cjs extensions
// fetch-wrapper.cjsconst fetch = (...args) =>import('node-fetch').then(({ default: fetch }) => fetch(...args));module.exports = { fetch };// usageconst { fetch } = require('./fetch-wrapper.cjs');fetch(url).then((result) => result.json());Error [ERR_REQUIRE_ESM]: require() of ES Module not supported
What this error means
Node.js keeps CommonJS (`require()`) and ES Modules (`import`) intentionally separate. When a package, like node-fetch v3 or strip-ansi v7, declares itself as ESM-only (via "type": "module" or a .mjs entry), Node refuses to load it with `require()` and raises ERR_REQUIRE_ESM. Bundlers such as Create React App, Next.js, or custom Webpack configs still emit CommonJS-style loading for server-side code, so the runtime hits this error as soon as an ESM-only dependency is pulled into a CommonJS loader. In React stacks, this often surfaces when dependencies are upgraded to ESM-only releases. Node-fetch switched to ESM in the 3.0.0 beta, while strip-ansi 7.0 made the same leap. Even if your source files are still CommonJS, transitive imports from your build or CLI tooling can end up inside a CommonJS context and trigger the error. Fixing it requires either adopting ES modules across the app, loading ESM dependencies asynchronously, or pinning to the latest CommonJS-friendly version.
Typical symptoms
- React dev server or build fails with "Error [ERR_REQUIRE_ESM]: require() of ES Module not supported"
- Server-side rendering (Next.js API routes / pages) crashes before the first render
- Unit tests break with "Must use import to load ES Module" messages
- Console output shows the offending package path (node_modules/node-fetch or strip-ansi)
- CI job that bundles the React app fails during npm install or webpack compile
- Dependencies that previously worked start failing after a patch release
Common causes
- An ESM-only package (node-fetch v3+, strip-ansi v7, chalk v5+) is being require()-loaded
- "type": "module" is set in a dependency, but the consuming code still uses require()
- React build tooling emits CommonJS wrappers around ESM dependencies (e.g., CRA server.js)
- Mixed module syntax where helper scripts remain CommonJS while new code uses import
- Bundler config does not list .mjs/.cjs extensions or cannot handle asynchronous imports
- Transitive dependency upgrade (strip-ansi, node-fetch, ansi-styles) introduced ESM-only artifacts
How to fix "Error [ERR_REQUIRE_ESM]: require() of ES Module not supported"
Wrap the ESM dependency in a helper that uses import(), which works from CommonJS:
// fetch-wrapper.cjs
const fetch = (...args) =>
import('node-fetch').then(({ default: fetch }) => fetch(...args));
module.exports = { fetch };
// usage
const { fetch } = require('./fetch-wrapper.cjs');
fetch(url).then((result) => result.json());Node-fetch 3+ dropped CommonJS in favor of ES modules, so require('node-fetch') now throws ERR_REQUIRE_ESM. Use this wrapper to keep the rest of your code CommonJS while loading the module asynchronously.
If your React project can move to ESM, update package.json:
{
"type": "module"
}Then replace require() with import/ export and include extensions on relative imports:
import React from 'react';
import App from './App.js';
export default App;Update build scripts (Webpack, Babel, jest) to handle .js/.jsx/.mjs/.cjs and enable module: "ES2020", moduleResolution: "node" in tsconfig. Next.js and CRA also support ESM entry files for API routes once they export with export default.
Temporarily downgrade the dependency until you can migrate tooling:
npm install node-fetch@2.6.7
npm install strip-ansi@6.0.1
# or, with yarn:
# yarn add node-fetch@^2.6.7 strip-ansi@^6.0.1Node-fetch v2 and strip-ansi v6 are still CommonJS. Use overrides or Yarn resolutions if the package is pulled in transitively:
{
"overrides": {
"strip-ansi": "6.0.1"
}
}This lets the build succeed while you plan a permanent fix.
If the project uses "type": "module" but builds still require CommonJS configs (Webpack, Jest), rename them to .cjs:
mv webpack.config.js webpack.config.cjs
mv jest.config.js jest.config.cjsThen update your package.json scripts:
{
"scripts": {
"build": "webpack --config webpack.config.cjs"
}
}Files ending with .cjs are always interpreted as CommonJS, letting tooling still call require() without hitting ERR_REQUIRE_ESM.
Configure Webpack or Vite to handle .mjs and conditional exports so it can load ESM packages cleanly:
// webpack.config.js
module.exports = {
resolve: {
extensions: ['.tsx', '.ts', '.jsx', '.js', '.mjs', '.cjs'],
conditionNames: ['require', 'import', 'default']
}
};If a package.json exposes both import and require entry points, the bundler must pick the right one. Webpack 5 and Vite do this automatically if you include .mjs in resolve extensions and avoid forcing mainFields to CommonJS-only entries.
Advanced notes
Node 18+ now ships with the WHATWG fetch API, so React servers running on a modern Node version can drop node-fetch entirely. For other runtimes, packages such as Got, Axios, or isomorphic-fetch stay CommonJS. When migrating, be careful with dual-package distributions: importing the ESM entry in some places and the CJS entry elsewhere can create duplicate instances, which breaks checks like instanceof React.Component. Finally, tools like esm-hook or ts-node --esm can smooth the transition but add extra transpilation steps.
Frequently asked questions
- What does "ERR_REQUIRE_ESM" mean?
- js keeps CommonJS (require()) and ES Modules (import) intentionally separate. mjs entry), Node refuses to load it with require() and raises ERR_REQUIRE_ESM. js, or custom Webpack configs still emit CommonJS-style loading for server-side code, so the runtime hits this error as soon as an ESM-only dependency is pulled into a CommonJS loader.
- How do I fix "ERR_REQUIRE_ESM"?
- A React build or runtime throws "require() of ES modules is not supported" when CommonJS code tries to load an ES module (for example node-fetch v3 or strip-ansi v7) because Node enforces module system compatibility and CRA/Next builds still emit require().
- What causes "ERR_REQUIRE_ESM"?
- An ESM-only package (node-fetch v3+, strip-ansi v7, chalk v5+) is being require()-loaded "type": "module" is set in a dependency, but the consuming code still uses require() React build tooling emits CommonJS wrappers around ESM dependencies (e.g., CRA server.js)
- Is the "ERR_REQUIRE_ESM" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.