Skip to content
Latchkey

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.

Node output
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.

JS
import pkg from 'cjs-pkg';
const { something } = pkg;
something();

Confirm the export shape

  1. Check whether the package ships ESM or CommonJS (its exports/main).
  2. For CJS, use a default import; for true ESM, named imports work.
  3. For TS, enable esModuleInterop so 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.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →