Skip to content
Commitpedia
Log in Join & edit

Fix: SyntaxError: Cannot use import statement outside a module

The file uses ES module import syntax, but Node or the browser is loading it as a classic script or CommonJS. Tell the runtime the file is a module.

Drafted with AI from official documentation. Scripts were run in a test environment and repository links verified. Awaiting a human check. Did it work for you? Last edited Outdated?

Edit history of Fix: SyntaxError: Cannot use import statement outside a module: 1 recorded edit
Edit history · 1 edit
Type
Article
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Reading
2 min

You see this when a file contains import ... from ... but is executed as CommonJS (in Node) or as a classic script (in the browser):

import { readFile } from "node:fs/promises";
^^^^^^

SyntaxError: Cannot use import statement outside a module

Why it happens

JavaScript has two module systems. ES modules (ESM) use import/export and are the standard in browsers and modern Node. CommonJS (CJS) uses require()/module.exports and was Node’s original system. Node decides which one a file uses before running it:

  • .mjs files are always ESM; .cjs files are always CommonJS.
  • .js files follow the "type" field in the nearest package.json: "module" means ESM, "commonjs" means CommonJS.
  • With no "type" field, recent Node versions (22.7 and later) try to detect ESM syntax automatically; older versions treat the file as CommonJS and throw this error.

So the error usually means the file is a .cjs file, the package says "type": "commonjs", or you are on an older Node.

Fix in Node

Pick one of these, in order of preference:

  1. Add "type": "module" to your package.json. All .js files in that package become ES modules.
  2. Or rename just that file to .mjs.
  3. Or, if the project must stay CommonJS, use require() in that file, or load an ES-only package with dynamic await import("pkg") inside an async function.
{
  "name": "my-app",
  "type": "module"
}

Things that change after switching to ESM

  • require, module.exports, __dirname and __filename do not exist. Use import/export, and import.meta.dirname / import.meta.filename (Node 20.11+).
  • Relative imports need the file extension: import { x } from "./utils.js", not "./utils".
  • Importing JSON needs an import attribute: import data from "./data.json" with { type: "json" }.
  • Importing a CommonJS package gives you its module.exports as the default export; named imports work only when Node can detect them statically.
  • Any remaining CommonJS files can be renamed to .cjs so they keep working.

Going the other way, Node 20.19+ and 22.12+ can require() a synchronous ES module, which makes mixed projects much easier than they used to be.

Fix in the browser

A plain <script> tag loads a classic script. Mark it as a module:

<script type="module" src="/js/app.js"></script>

Module scripts are deferred automatically and run in strict mode, and they only load over HTTP(S). Opening the page from file:// usually fails because of CORS rules, so use a local dev server.

Fix in tools and test runners

  • TypeScript: check "module" in tsconfig.json. For Node projects, "module": "nodenext" makes the compiled output follow your package.json type.
  • ts-node: this error is a common symptom of ESM projects run with the CommonJS loader. Alternatives are tsx or Node’s built-in type stripping.
  • Jest: it runs CommonJS by default and transforms your code; an ES-only dependency in node_modules is not transformed. Adjust transformIgnorePatterns, enable Jest’s ESM support, or use a runner with native ESM such as Vitest or node --test.

Did this work for you?

No votes yet. Be the first.

If it did not work, the report form below tells the editors what went wrong.

See also

Repos in the wild

  • Node.js nodejs/node The source of the Node.js runtime: a JavaScript engine (V8) plus APIs for files, networking, processes and more, used to run JavaScript outside the browser. GitHub
  • Express (expressjs/express) expressjs/express A minimal and flexible web framework for Node.js, built around routes and middleware, and the foundation of countless APIs and other frameworks. GitHub

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Dominik +3,110 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?