Requiring an ES Module

For years require('./thing.mjs') threw ERR_REQUIRE_ESM and the ecosystem split in half over it. Node now loads an ES module from require() as long as the module's whole graph is synchronous. The feature landed behind --experimental-require-module in 22.0.0, became the default in 23.0.0 and was declared stable in 25.4.0. It is what lets a CommonJS Express 5 24,430 server pull in an ESM-only utility package.

main.cjs -- calling into an ES module from CommonJSJavaScript
const ns = require('./point.mjs');
console.log(ns);
console.log(ns.distance({ x: 0, y: 0 }, { x: 3, y: 4 }));
try { require('./slow.mjs'); }       // slow.mjs uses top-level await
catch (err) { console.log(err.code); }
Output
[Module: null prototype] {
  __esModule: true,
  default: [class Point] { distance: [Function: distance] },
  distance: [Function: distance]
}
5
ERR_REQUIRE_ASYNC_MODULE

What comes back is the module namespace object, so a default export arrives as .default. That is the common surprise: const Point = require('./point.mjs') gives you the namespace. Node sets __esModule: true on it so transpiler interop helpers recognize it.

slow.mjs has a top-level await, so it cannot be evaluated synchronously and ERR_REQUIRE_ASYNC_MODULE is thrown; the only fix at the call site is await import(). When the offending await is buried in a dependency, run once with --experimental-print-required-tla and Node prints its locations instead of evaluating the graph.

A package author can hide the difference by exporting a binding under the string name 'module.exports':

Making require() of an ES module return the default directlyShell
export function distance(a, b) { return Math.hypot(b.x - a.x, b.y - a.y); }
export default class Point {
  constructor(x, y) { this.x = x; this.y = y; }
  static distance = distance;
}
export { Point as 'module.exports' };

Now require('./point.mjs') returns the class itself. The catch is that named exports disappear for CommonJS callers, which is why distance is also a static property; import consumers see them either way.