Comprehensive Guide to Resolving ERR_REQUIRE_ESM Error in Node.js

Nov 08, 2025 · Programming · 22 views · 7.8

Keywords: Node.js | ES Modules | CommonJS | ERR_REQUIRE_ESM | Module Migration

Abstract: This article provides an in-depth exploration of the common ERR_REQUIRE_ESM error in Node.js environments, thoroughly analyzing compatibility issues between ES modules and CommonJS modules. Through practical Discord bot development examples, it systematically introduces three solutions: using ESM import syntax, downgrading node-fetch versions, and configuring package.json module types. The article also covers advanced topics including TypeScript configuration and Jest testing environment adaptation, offering developers comprehensive guidance for module system migration.

Problem Background and Error Analysis

In Node.js development environments, the evolution of module systems has introduced new compatibility challenges. The ERR_REQUIRE_ESM error typically occurs when attempting to use the require() function to import pure ES modules. The core root of this error lies in changes to Node.js's module resolution mechanism.

Starting from Node.js v12, ES module support has gradually matured, with many popular npm packages transitioning to pure ESM distribution. Taking node-fetch as an example, beginning with version 3.0.0, this package completely removed CommonJS support, offering only ES module format. When developers continue using traditional require('node-fetch') syntax, the ERR_REQUIRE_ESM error is triggered.

Core Solutions

For addressing the ERR_REQUIRE_ESM error, there are primarily three viable solutions, each with its applicable scenarios and considerations.

Solution 1: Using ESM Import Syntax

This is the most recommended long-term solution. Replace require statements in code with ESM's import syntax:

// Before replacement
const fetch = require('node-fetch');

// After replacement
import fetch from "node-fetch";

To make this solution effective, module type declaration needs to be added to package.json:

{
  "type": "module"
}

This configuration tells Node.js to treat all .js files as ES modules. It's important to note that once this configuration is enabled, all modules in the project must use ESM syntax and can no longer mix require statements.

Solution 2: Downgrading Dependency Versions

For scenarios requiring quick problem resolution without extensive code refactoring, consider downgrading to older versions that support CommonJS:

npm install node-fetch@2.6.6

This method can immediately resolve the issue but carries long-term maintenance risks. Older versions may lack security updates and new features, and future upgrades will still require addressing module system migration.

Solution 3: Using Alternative HTTP Client Libraries

If the project doesn't have strong dependencies on node-fetch, consider using other HTTP client libraries that support CommonJS:

# Using axios
npm install axios

# Or using got
npm install got

These libraries maintain good CommonJS support in current versions and can seamlessly replace node-fetch functionality.

Practical Application Case

Using a Discord bot's game status query functionality as an example, demonstrating the complete ESM migration process. Original code using CommonJS modules:

module.exports = {
  name: 'username',
  description: "this is the username command",
  async execute(message, args) {
    const fetch = require('node-fetch');
    // ... remaining business logic
  }
};

Code structure after migrating to ESM:

import fetch from 'node-fetch';

export default {
  name: 'username',
  description: "this is the username command",
  async execute(message, args) {
    // ... business logic remains unchanged
  }
};

TypeScript Environment Configuration

Handling ESM modules in TypeScript projects requires additional configuration considerations. Recommended to use predefined TypeScript configuration packages to simplify setup:

{
  "extends": "@tsconfig/node-lts/tsconfig.json",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src",
    "resolveJsonModule": true
  }
}

After enabling ESM, relative path imports require explicit file extensions:

// Correct
import { utility } from './utils.js';

// Incorrect (in ESM mode)
import { utility } from './utils';

JSON File Import Handling

Importing JSON files in ESM mode requires special handling:

import packageJson from '../package.json' with { type: 'json' };

This syntax may currently require TypeScript configuration support and might need temporary use of // @ts-ignore comments in some environments.

Testing Environment Configuration

When using Jest for testing, corresponding configuration file adjustments are needed to support ESM modules. Create a jest.config.cjs file:

const { createDefaultEsmPreset } = require("ts-jest");
const defaultEsmPreset = createDefaultEsmPreset();

module.exports = {
  testEnvironment: "node",
  ...defaultEsmPreset,
  moduleNameMapper: {
    "^(\.{1,2}/.*)\.js$": "$1"
  }
};

Note that the configuration file uses the .cjs extension to ensure proper loading in ESM projects.

Best Practice Recommendations

Based on practical project experience, the following recommendations are proposed:

Gradual Migration Strategy: For large projects, recommend adopting gradual migration. Start by using ESM in new features and gradually replace existing modules.

Dependency Audit: Regularly check module system support for project dependencies to avoid unexpected interruptions due to dependency updates.

Team Training: Ensure development teams are familiar with differences between ESM and CommonJS, establishing unified coding standards.

Build Tool Configuration: If using build tools like Webpack or Vite, ensure relevant configurations can properly handle both module systems.

Conclusion

The ERR_REQUIRE_ESM error reflects the evolution of module systems in the JavaScript ecosystem. While short-term migration costs may exist, long-term unified use of ESM modules benefits cross-platform compatibility and maintainability. Through reasonable migration strategies and tool configurations, developers can smoothly transition to modern module systems and enjoy their numerous advantages.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.