Skip to content

Node.js and JavaScript errorSyntaxError: “Cannot use import statement outside a module”

A script, a test run or a server start fails with SyntaxError: Cannot use import statement outside a module. The file uses import, but whatever runs it is treating it as an old-style CommonJS script. In Node.js that decision comes from package.json and the file extension; in a browser it comes from the script tag; in Jest it comes from the transform settings.

Short answer

In Node.js, add "type": "module" to the nearest package.json, or rename the file to .mjs. If the project has to stay CommonJS, switch the file to require() or rename it .cjs. In the browser, load the script with <script type="module">. In Jest, use a transform such as babel-jest or ts-jest, or run Jest with NODE_OPTIONS=--experimental-vm-modules and transform: {}, because it runs files as CommonJS by default.

Why the import is rejected, and the fix

  1. 01

    Node.js reads the .js file as CommonJS

    “Files ending with .js are loaded as ES modules when the nearest parent package.json file contains a top-level field "type" with a value of "module".” Node.js, Modules: Packages

    Without a "type" field, Node.js treats .js files as CommonJS. Add "type": "module" to package.json, or use the .mjs extension for the files that use import. Then switch any require(), module.exports and __dirname in those files to their ES module forms.

    // package.json
    {
      "type": "module"
    }
  2. 02

    Mixing both styles in one project

    “Regardless of the value of the "type" field, .mjs files are always treated as ES modules and .cjs files are always treated as CommonJS.” Node.js, Modules: Packages

    The extension always wins over the "type" field: .mjs is always an ES module and .cjs is always CommonJS. That lets you keep one config file or legacy script in the other style without changing the whole project.

  3. 03

    The tool running the file decides, not Node.js

    “Ensure you either disable code transforms by passing transform: {} or otherwise configure your transformer to emit ESM rather than the default CommonJS (CJS).” Jest, ECMAScript Modules

    Node.js 22.7 and 20.19 and later detect import syntax in .js files with no "type" field. On older Node, or with "type": "commonjs", the error still comes from Node itself. Test runners and browsers decide for themselves: Jest runs tests as CommonJS, so babel-jest or ts-jest compile import to require, or you turn on Jest’s experimental ES module support (below). A browser script tag without type="module" fails the same way.

    # Jest with native ES modules (experimental)
    NODE_OPTIONS="--experimental-vm-modules" npx jest
    
    <!-- browser: tell it the script is a module -->
    <script type="module" src="/main.js"></script>
  4. 04

    The explicit markers Node.js understands

    “Authors can tell Node.js to interpret JavaScript as an ES module via the .mjs file extension, the package.json "type" field with a value "module"” Node.js, Modules: ECMAScript modules

    If you are not sure which rule applies, make it explicit: the .mjs extension, "type": "module" in package.json, or --input-type=module for code passed on the command line. TypeScript projects also need module settings in tsconfig.json that match what Node.js expects.

Checked against the vendor’s docs on : Node.js: Modules: Packages (the "type" field, .mjs and .cjs, syntax detection); Node.js: Modules: ECMAScript modules; Jest: ECMAScript Modules (experimental support).

Rather hand it over?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

Related: Node.js ERR_OSSL_EVP_UNSUPPORTED · Vite “Failed to load module script” · Vercel npm run build exited with 1 · Node.js “Cannot find module”

Questions

More on this error

Will adding "type": "module" break other files?

It can. Every .js file in that package is then read as an ES module, so files that use require() or module.exports stop working. Rename those to .cjs, or convert them to import and export.

Why does it work in the browser but fail in my tests?

The bundler handles import for the browser build. The test runner runs files on its own, and Jest uses CommonJS by default, so it needs a transform (babel-jest or ts-jest) or its experimental ES module support: transform: {} in the Jest config and Node run with --experimental-vm-modules.

Can you fix it for me?

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

A different error?

Describe it and get a written quote

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.