Node.js "Cannot find module 'node-fetch'" (ESM-only v3) in CI
By Kaveh Alemi·Latchkey
node-fetch v3+ is published as ESM only. CommonJS code that require("node-fetch") either cannot resolve it or throws ERR_REQUIRE_ESM, breaking the build.
What this error means
After upgrading node-fetch, a CommonJS project fails on require("node-fetch") with a module-not-found or ERR_REQUIRE_ESM error in CI.
node
Error [ERR_REQUIRE_ESM]: require() of ES Module
/work/repo/node_modules/node-fetch/src/index.js from
/work/repo/src/http.js not supported.
code: 'ERR_REQUIRE_ESM'
Diagnose it: what is different about the runner?
A build that passes locally and fails on a runner differs in a small number of predictable ways. Check those before changing build configuration, because the build config is usually not the thing that changed.
Version 3 ships ESM only. A CommonJS project that upgrades can no longer require it synchronously.
Native fetch makes node-fetch unnecessary
Modern Node has a global fetch. Keeping node-fetch at all is often avoidable and the source of the ESM mismatch.
How to fix it
Use the built-in global fetch
Drop the dependency entirely on Node 18+, which provides fetch globally.
src/http.js
// remove node-fetch import
const res = await fetch('https://example.com');
const data = await res.json();
Or pin node-fetch v2 for CommonJS
If you must keep node-fetch in a CommonJS project, pin v2, which still ships CommonJS.
Terminal
npm install node-fetch@2
The three that account for most of them
Case sensitivity. Linux runners are case sensitive, macOS is not. An import with the wrong case resolves locally and fails in CI.
Out of memory. Exit code 137 is a SIGKILL from the kernel, not a build error. Raise --max-old-space-size or use a larger runner.
devDependencies pruned.NODE_ENV=production makes npm ci skip devDependencies, so the build tool itself goes missing. Set it after install, not before.
How to prevent it
Prefer the global fetch on Node 18+ and remove node-fetch.
Read changelogs for ESM-only majors before upgrading.
Keep one module system across the project.
Frequently asked questions
What causes Node.js "Cannot find module 'node-fetch'" (ESM-only v3) in CI?
There are 2 common causes: node-fetch v3 dropped commonjs and native fetch makes node-fetch unnecessary. Version 3 ships ESM only.
How do I fix Node.js "Cannot find module 'node-fetch'" (ESM-only v3) in CI?
There are 2 fixes depending on which cause you have: use the built-in global fetch and or pin node-fetch v2 for commonjs. Work through them in order, since the first is the most common.
What does Node.js "Cannot find module 'node-fetch'" (ESM-only v3) in CI actually mean?
After upgrading node-fetch, a CommonJS project fails on require("node-fetch") with a module-not-found or ERR_REQUIRE_ESM error in CI.
How do I stop Node.js "Cannot find module 'node-fetch'" (ESM-only v3) in CI happening again?
Prefer the global fetch on Node 18+ and remove node-fetch. The prevention section lists 3 changes that keep it from recurring.