All guides

LEARN \u00b7 DEBUGGING GUIDE

ESM CommonJS import error: how to debug module system conflicts

You `import` a package and get 'require is not defined in ES module scope'. Or you `require()` a module and get 'Cannot use import statement outside a module'. Node.js thinks your code is one module system, but it is written as the other.

IntermediateJavaScript/Node runtime debugging

What this usually means

Node.js supports two module systems: CommonJS (CJS, using `require()` and `module.exports`) and ECMAScript Modules (ESM, using `import` and `export`). Node determines which system a file uses by: the `type` field in the nearest `package.json` (`type: 'module'` makes `.js` files ESM), the file extension (`.mjs` is always ESM, `.cjs` is always CJS), or the package's own module format. Problems happen when you use `import` in a CJS context, `require()` in an ESM context, or when a dependency ships code for one system but your project expects the other.

( 01 )Fast diagnosis

The first ten minutes \u2014 establish facts before touching code.

  • 1Check the nearest `package.json` `type` field. If `type: 'module'`, `.js` files are ESM and cannot use `require()`. If no type or `type: 'commonjs'`, `.js` files are CJS and cannot use top-level `import`.
  • 2Check the file extension. `.mjs` is always ESM. `.cjs` is always CJS. `.js` depends on `package.json`.
  • 3Check if you are mixing `import` and `require()` in the same file. ESM files can use `import()` (dynamic import) but not `require()`.
  • 4Check the dependency's module format. Some packages ship both ESM and CJS. Your bundler or runtime picks one based on the `exports` field in the package's `package.json`.
  • 5Check if the error happens only when running directly with Node.js (not through a bundler). Bundlers can handle mixed module formats that Node.js cannot.
( 02 )Where to look

The specific files, logs, configs, and dashboards that usually own this bug.

  • search`package.json` — `type` field, `exports` field, `main` and `module` fields
  • searchThe failing file — its extension and import/require statements
  • searchThe imported package's `package.json` — `type`, `exports`, `main`, `module`
  • searchNode.js version — ESM support matured between Node 12 and Node 20
  • searchBundler or transpiler config — Webpack, Vite, tsup, esbuild settings
  • searchBuild output — compiled `.js` files may have different module format than source
( 03 )Common root causes

Practical causes, not theory. These are the things you will actually find.

  • warning`type: 'module'` in package.json but using `require()` in `.js` files
  • warningNo `type` field and using `import` in `.js` files (Node treats them as CJS)
  • warningImporting a CJS package that uses `module.exports` with a named ESM import `import { foo }` — CJS exports might not be statically analysable
  • warningA dependency ships only ESM but your project is CJS (or vice versa)
  • warningTypeScript `compilerOptions.module` does not match the runtime module system
  • warningPackage `exports` field restricts which files can be imported and how
( 04 )Fix patterns

Concrete fix directions. Pick the one that matches your root cause.

  • buildRename file to `.mjs` (for ESM) or `.cjs` (for CJS) to override the package.json type
  • buildSet `type: 'module'` or `type: 'commonjs'` explicitly in package.json — do not rely on default
  • buildUse `import()` (dynamic import) to load CJS modules from ESM files
  • buildUse `createRequire` from `module` to use `require()` inside an ESM file: `import { createRequire } from 'module'; const require = createRequire(import.meta.url);`
  • buildFor CJS packages imported in ESM, use default import: `import pkg from 'cjs-package'` then destructure
  • buildCheck the package's documentation for the recommended import syntax for each module system
( 05 )How to verify

A fix you cannot prove is a guess. Close the loop.

  • verifiedRun the file with `node <file>` directly. It should work without a bundler.
  • verifiedTest both `import` and `require()` paths if the module supports both.
  • verifiedRun in CI on the same Node.js version as production.
  • verifiedCheck the build output — the compiled file should use the module system the runtime expects.
  • verifiedWrite a simple test that imports the problematic module and verifies it works.
( 06 )Mistakes to avoid

Things that make this bug worse or harder to find.

  • warningMixing `import` and `require()` in the same file without understanding the module context
  • warningAssuming all packages support both ESM and CJS — many ship only one
  • warningNot setting `type` in package.json and relying on default behaviour
  • warningUsing a bundler for development but running unbundled in production (or vice versa)
  • warningRenaming `.js` to `.mjs` without updating all imports that reference the file