require('node-fetch') gives ERR_REQUIRE_ESM

Viewed 49221

I just use

const fetch = require('node-fetch')

And I get

Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\Alex\Desktop\rollbot\node_modules\node-fetch\src\index.js from C:\Users\Alex\Desktop\rollbot\index.js not supported.
Instead change the require of C:\Users\Alex\Desktop\rollbot\node_modules\node-fetch\src\index.js in C:\Users\Alex\Desktop\rollbot\index.js to a 
dynamic import() which is available in all CommonJS modules.
{
  code: 'ERR_REQUIRE_ESM'
}

All my other packages work, just node-fetch does this. What should I do in order to use node-fetch?

6 Answers

From the node-fetch package readme:

node-fetch is an ESM-only module - you are not able to import it with require. We recommend you stay on v2 which is built with CommonJS unless you use ESM yourself. We will continue to publish critical bug fixes for it.

If you want to require it, then downgrade to v2.

The other option you have is to use async import('node-fetch').then(...)

What I found is that the latest version of node-fetch changed to ES modules by default. You can:

  1. Uninstall the current version of node-fetch with npm uninstall node-fetch
  2. Install the second version: npm install node-fetch@2

It has worked for me!

In my case, I personally found it easier to require ('cross-fetch') instead. The documentation is here: cross-fetch

It can be used in CommonJS as well as ES6 modules.

LATEST UPDATE MAY 2022

You may not needed node-fetch anymore.

In the latest version of Node.js (18.0.0), global fetch (experimental) is enabled by default.

const res = await fetch('https://nodejs.org/api/documentation.json');
if (res.ok) {
  const data = await res.json();
  console.log(data);
}

Through this addition, the following globals are made available: fetch, FormData, Headers, Request, Response.

You may disable this API with the --no-experimental-fetch command-line flag.

You can use node-fetch@3 from CommonJS using dynamic imports. Since fetch is already an async API you can define a wrapper like this:

fetch.js

exports.fetch = async function (url, init) {
    const {default: fetch} = await import("node-fetch");
    return await fetch(url, init);
};

You can then use the wrapper like this:

const fetch = require("./fetch");

This trick doesn't work out of the box in TypeScript since TypeScript transforms the dynamic import to a regular require. To work around this just add the plain fetch.js to your project and also add a type declaration:

fetch.d.ts

/**
 * @param { import("node-fetch").RequestInfo} url
 * @param {import("node-fetch").RequestInit} init
 * @returns {Promise<import("node-fetch").Response>}
 */
export function fetch(
    url: import("node-fetch").RequestInfo,
    init: import("node-fetch").RequestInit
): Promise<import("node-fetch").Response>;

cross-fetch is a nice alternative but it's wrapping a 2.x version of node-fetch so you won't get the latest version.

Related