Node CJS/ESM Interop - "is not a function" on a Default Import
When ESM imports a CommonJS package, Node wraps module.exports as the default export. Importing named bindings that do not exist as ESM named exports leaves them undefined, so calls throw "is not a function".
What this error means
Under ESM, a call to a function imported from a CommonJS dependency throws "X is not a function" or "default is not a function". The same code worked under CommonJS require, but the import shape is now wrong.
import { something } from 'cjs-pkg';
something();
// TypeError: something is not a function
// (cjs-pkg only has a default/module.exports, no ESM named export)Common causes
Named import from a CommonJS module
CommonJS exports become the ESM default. Destructuring a named import that the package does not expose as an ESM named export yields undefined.
Mismatched default vs namespace import
Some CJS packages need import pkg from "..." (default), others a namespace import. Using the wrong form gives an object/undefined instead of the callable.
How to fix it
Import the default, then destructure
Take the default export of the CJS module and pull members off it.
import pkg from 'cjs-pkg';
const { something } = pkg;
something();Confirm the export shape
- Check whether the package ships ESM or CommonJS (its
exports/main). - For CJS, use a default import; for true ESM, named imports work.
- For TS, enable
esModuleInteropso default imports of CJS behave consistently.
How to prevent it
- Match import style to the package’s module format.
- Enable esModuleInterop in TS for CJS interop.
- Test imports of upgraded deps in CI.