SyntaxError: Cannot use import statement outside a module
The file uses import, but whatever is running it thinks it is an old-style CommonJS script (or, in a browser, a classic script). Tell the runtime the file is an ES module, or stop mixing the two systems.
Two module systems
| CommonJS (CJS) | ES modules (ESM) | |
|---|---|---|
| Syntax | const x = require('x'), module.exports | import x from 'x', export |
| Node picks it when | .cjs, or .js with no "type" / "type": "commonjs" | .mjs, or .js with "type": "module" |
| Browser | Not supported natively | <script type="module"> |
The error means an import line landed in code the runtime is treating as the left-hand column.
Fix in Node
// package.json (nearest one to the file)
{
"type": "module"
}
Or rename just that file to file.mjs. After switching, the reverse problems appear: require is not defined in ES module scope (use import, or createRequire from node:module), __dirname is not defined (use import.meta.dirname on Node 20.11+, or path.dirname(fileURLToPath(import.meta.url))), and relative imports need the extension: import './util.js', not './util'. Recent Node versions (22.12+) can also require() many ES modules, which softens some of this.
Validate the edited package.json in the JSON formatter: a stray comma there produces a different, more confusing error.
Fix in the browser
<!-- wrong: classic script -->
<script src="/app.js"></script>
<!-- right -->
<script type="module" src="/app.js"></script>
Module scripts are deferred automatically, run in strict mode, and must be served over HTTP(S) with a JavaScript MIME type. Opening the page from file:// triggers a CORS error instead, so use a local dev server. Bare imports like import React from 'react' do not work in the browser without a bundler (Vite, esbuild) or an import map.
Fix in TypeScript and ts-node
- The compiled output must match how Node runs it. Modern setups use
"module": "NodeNext"and"moduleResolution": "NodeNext"intsconfig.json, which follows"type"in package.json. - ts-node in an ESM project needs its ESM loader (
node --loader ts-node/esm), or switch totsx, which handles both without config. - Node 22.6+ can run simple
.tsfiles directly with type stripping; the same"type"rules apply.
Fix in Jest
Jest runs tests as CommonJS by default. Either let Babel or ts-jest transform import into require, or run Jest in native ESM mode (NODE_OPTIONS=--experimental-vm-modules npx jest). When the failing file is inside node_modules (an ESM-only package), add it to transformIgnorePatterns exceptions, or move to Vitest, which is ESM-first.
When it is inside a dependency
If the stack trace points into node_modules/some-package, that package became ESM-only in a major version. Options: import it from an ESM file, use dynamic await import('some-package') from CJS, or pin the last CommonJS major. Compare the two lockfiles in the text diff tool to see which version jumped.
Related
npm ERR! code ENOENT · ModuleNotFoundError (Python) · Node OpenSSL digital envelope error · Refused to execute inline script (CSP) · npm ERR! code ELIFECYCLE · Module not found: Can't resolve · Cannot find module (Node)
Questions
What causes 'Cannot use import statement outside a module'?
An import statement is in a file that Node, Jest or the browser is running as CommonJS or a classic script. Mark the file as an ES module or convert the import to require.
How do I fix it in Node.js?
Add "type": "module" to the nearest package.json, or rename the file to .mjs. Then use file extensions in relative imports and import.meta instead of __dirname.
How do I fix it in the browser?
Load the script with <script type="module" src="..."> and serve the page from a web server rather than file://.
Why does Jest show this error?
Jest uses CommonJS by default. Add a Babel or ts-jest transform, run Jest with --experimental-vm-modules, or switch to Vitest. ESM-only packages in node_modules also need a transformIgnorePatterns exception.
Can I mix require and import?
In an ES module, use createRequire to load CommonJS-only code. In CommonJS, use dynamic await import() for ESM-only packages. Newer Node versions can require() many ES modules directly.
Published .