SyntaxError: Cannot use import statement outside a module

Node.js · updated 2026-11-02

Thrown while Node parses a file, before any of it runs, when the file uses import or export but Node is treating it as CommonJS. Node decides per file: .mjs is ESM, .cjs is CommonJS, and .js follows the nearest package.json "type" field (CommonJS when it is missing). Test runners and TypeScript loaders add their own rules on top.

/srv/app/dist/server.js:1
import express from "express";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:76:18)
    at wrapSafe (node:internal/modules/cjs/loader:1283:20)
    at Module._compile (node:internal/modules/cjs/loader:1328:27)

Quick fix

Decide which module system the package uses and make Node agree. For ESM, add "type": "module" to the package.json next to the file (or rename the file to .mjs). For CommonJS, compile the import statements away (TypeScript "module": "commonjs") or switch them to require(). The stack trace path shows which file Node treated as CommonJS.

  1. Note the file in the first line of the error; that is the one Node parsed as CommonJS.
  2. Find the nearest package.json above it and check its "type" field.
  3. ESM project: set "type": "module", or use the .mjs extension for that file.
  4. CommonJS project: make the build emit CommonJS (tsconfig "module": "commonjs") or use require().
  5. Under Jest or ts-node, configure the transform or loader for ESM instead of changing app code.
json
{
  "name": "my-app",
  "type": "module",
  "scripts": { "start": "node dist/server.js" }
}

Why it happens

package.json has no "type": "module"

Without it, every .js file in the package is CommonJS, so the first import statement is a syntax error.

TypeScript emitted ESM into a CommonJS package

tsconfig "module": "esnext" (or "nodenext" with "type" unset) keeps import statements in dist/, which Node then loads as CommonJS.

A dependency ships ESM only and is loaded through a CommonJS path

Jest, ts-node and older bundlers transform your code but often not node_modules, so an ESM-only package fails inside the test or script runner.

Running a file from another package directory

Node uses the package.json nearest to the file, not the one in the working directory, so a script copied into a folder with its own package.json changes module type.

Other fixes

  • Pick one module system per package and set "type" explicitly either way.
  • For Jest, use its ESM support (NODE_OPTIONS=--experimental-vm-modules) or a transform that includes the ESM-only package.
  • Use .cjs and .mjs extensions for the odd file out instead of mixing styles in .js files.

Same error, other wording

  • SyntaxError: Unexpected token 'export'
  • Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.

Let your coding agent catch the next one

Runheed records this error in production with the stack trace, the breadcrumbs before it and the agent session that shipped the code, and serves it to Claude Code, Cursor or any MCP client. With it connected, you can ask:

> Find the "Cannot use import statement outside a module" errors in production or CI, name the file Node parsed as CommonJS and the release behind it, and decide whether the package should be ESM ("type": "module") or the build should emit CommonJS.

Plans from $29/moSee what your agent readsSee the setupCancel any time from the billing portal

Related errors

References: Node.js: Determining module system, Node.js: package.json "type"