Skip to content

Instead change the require of index.js, to a dynamic import() which is available in all CommonJS modules

Problem Statement

When working with Node.js, you may encounter the error:

javascript
error [ERR_REQUIRE_ESM]: require() of ES Module [...] is not supported. Instead change the require of index.js to a dynamic import() which is available in all CommonJS modules

This error occurs when you try to use require() to import an ES Module (ECMAScript Module) package in a CommonJS environment. Many modern npm packages have transitioned to ESM-only distribution, which breaks compatibility with the traditional require() syntax.

WARNING

The problem typically occurs with packages like node-fetch, chalk, and others that have migrated to ES Modules in their newer versions while your code remains in CommonJS format.

Solutions

The most straightforward solution is to replace require() with dynamic import(), which works in both CommonJS and ESM environments:

javascript
// Replace this:
const fetch = require('node-fetch');

// With this:
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));

For multiple imports, use async/await syntax:

javascript
async function main() {
  const { default: FormData } = await import('form-data');
  const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
  const { default: chalk } = await import('chalk');
  
  // Your code here
}

main().catch(console.error);

2. Convert to ES Modules

If you can modify your project structure, convert it to use ES Modules:

  1. Add to package.json:
json
{
  "type": "module"
}
  1. Change require to import:
javascript
// Replace:
const path = require("path");
const fs = require("fs");

// With:
import path from "path";
import fs from "fs";
  1. Use .mjs extension for your files, or keep .js with "type": "module" in package.json

3. Downgrade Package Version (Temporary Fix)

If you need a quick fix, downgrade to a CommonJS-compatible version:

bash
npm uninstall node-fetch
npm install node-fetch@2.6.1

DANGER

This approach is not recommended long-term as you'll miss security updates and new features. Use it only as a temporary solution.

4. Alternative Packages

Consider using alternative packages that support CommonJS:

bash
npm install node-fetch-native

This package provides a polyfilled version that works with both module systems.

Complete Example with Dynamic Import

Here's how to rewrite the original code using dynamic imports:

javascript
async function processFiles() {
  // Dynamic imports
  const FormData = (await import('form-data')).default;
  const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
  const path = await import('path');
  const fs = await import('fs');
  
  const basePath = process.cwd();
  
  const files = fs.readdirSync(`${basePath}/build/images`);
  
  for (const file of files) {
    try {
      const formData = new FormData();
      const fileStream = fs.createReadStream(`${basePath}/build/images/${file}`);
      formData.append('file', fileStream);

      const url = 'https://api.nftport.xyz/v0/files';
      const options = {
        method: 'POST',
        headers: {
          Authorization: '[...]',
        },
        body: formData
      };
      
      const response = await fetch(url, options);
      const json = await response.json();
      const fileName = path.parse(json.file_name).name;
      const rawdata = fs.readFileSync(`${basePath}/build/json/${fileName}.json`);
      const metaData = JSON.parse(rawdata);

      metaData.file_url = json.ipfs_url;

      fs.writeFileSync(`${basePath}/build/json/${fileName}.json`, JSON.stringify(metaData, null, 2));

      console.log(`${json.file_name} uploaded & ${fileName}.json updated!`);
    } catch (err) {
      console.error('Error processing file:', file, err);
    }
  }
}

processFiles().catch(console.error);

Additional Considerations

  • Node.js Version: Ensure you're using a recent Node.js version (v14.8.0+ for top-level await support)
  • TypeScript Configuration: If using TypeScript, ensure your tsconfig.json is configured appropriately:
json
{
  "compilerOptions": {
    "module": "commonjs" // or "ESNext" if converting to ESM
  }
}
  • Error Handling: Always wrap dynamic imports in try/catch blocks for proper error handling

Conclusion

The ERR_REQUIRE_ESM error occurs when mixing CommonJS and ES Module systems. The recommended solution is to use dynamic imports (import()) which work in both environments. For long-term projects, consider migrating to ES Modules by adding "type": "module" to your package.json and converting all require() statements to import syntax.