This error means Node.js is loading your file as a CommonJS module, but the file contains import syntax, which only works in ES modules. The fix is to add "type": "module" to your package.json, rename the file to .mjs, or convert the code to use require().
Why it happens
Node.js has two module systems:
- CommonJS (CJS) β the original Node.js format, using
require()andmodule.exports. This is the default: any.jsfile is treated as CJS unless told otherwise. - ES Modules (ESM) β the JavaScript standard, using
importandexport. Node.js uses ESM for.mjsfiles, and for.jsfiles whenpackage.jsoncontains"type": "module".
When you write import in a file that Node.js resolves as CommonJS, you get the error. The most common trigger is a package.json created by npm init β it has no type field, which means CommonJS by default.
Reproducing the error
Start with a fresh project:
mkdir myapp && cd myapp
npm init -y
The generated package.json has no type field. Now write a file using ES module syntax:
// app.js
import { createServer } from 'http';
const server = createServer((req, res) => { res.end('hello'); });
console.log('server created');
Running it with "type": "commonjs" in package.json (or with any .cjs file):
$ node app.js
(node:977512) Warning: Failed to load the ES module: /tmp/blogtest/app.js.
Make sure to set "type": "module" in the nearest package.json file or use the .mjs extension.
/tmp/blogtest/app.js:1
import { createServer } from 'http';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at wrapSafe (node:internal/modules/cjs/loader:1637:18)
at Module._compile (node:internal/modules/cjs/loader:1679:20)
...
Node.js v22.22.2
Node 22: warning instead of error (but still a problem)
In Node.js 22 with a typeless package.json (no type field at all), the hard error is replaced by a warning and the code still runs:
$ node app.js
server created
(node:977290) [MODULE_TYPELESS_PACKAGE_JSON] Warning: Module type of file:///tmp/myapp/app.js
is not specified and it doesn't parse as CommonJS.
Reparsing as ES module because module syntax was detected. This incurs a performance overhead.
To eliminate this warning, add "type": "module" to /tmp/myapp/package.json.
This is better than a crash, but "this incurs a performance overhead" means Node re-parses your file on every startup. Fix it properly rather than leaving the warning.
Fix 1: Add "type": "module" to package.json (recommended for new projects)
Open package.json and add one line:
{
"name": "myapp",
"version": "1.0.0",
"type": "module"
}
Now all .js files in the project are treated as ES modules:
$ node app.js
server created
No error, no warning. Use this fix when you are starting a new project and want to use import/export throughout.
Fix 2: Rename the file to .mjs
The .mjs extension always means ES module, regardless of package.json. This is useful when you want a single ESM file inside an otherwise CommonJS project:
$ mv app.js app.mjs
$ node app.mjs
server created
The rest of your .js files continue to use require() as normal.
Fix 3: Convert to CommonJS syntax
If the file needs to stay CommonJS β or you are working in a legacy codebase β replace import with require():
// Before β ES module syntax, causes the error
import { createServer } from 'http';
// After β CommonJS syntax, works everywhere
const { createServer } = require('http');
$ node app.cjs
server created (CommonJS)
The reverse error: require is not defined in ES module scope
Once you set "type": "module", any file that still uses require() will fail with a different error:
$ node legacy.js
file:///tmp/myapp/legacy.js:1
const path = require('path');
^
ReferenceError: require is not defined in ES module scope, you can use import instead.
This file is being treated as an ES module because it has a '.js' file extension
and '/tmp/myapp/package.json' contains "type": "module".
To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
Again, Node's error message tells you exactly what to do: either convert require() to import, or rename the file to .cjs.
Bonus: dynamic import() works in CommonJS files
If you need to load an ES module from inside a .cjs file β for example during a gradual migration β use the dynamic import() function:
// util.cjs β stays CommonJS
async function main() {
const { default: path } = await import('path');
console.log(path.join('/foo', 'bar'));
}
main();
$ node util.cjs
/foo/bar
import() is async and returns a Promise, so it needs an async function or a .then() chain. It is the bridge when you cannot convert an entire file at once.
Which fix to use
- New project using
importeverywhere: add"type": "module"topackage.json. - One ESM file in a CJS project: rename it to
.mjs. - File must stay CJS: convert
importtorequire(), rename to.cjsif needed, or use dynamicimport()for async loading. - Seeing the Node 22 warning: add
"type": "module"β do not leave it typeless.
Confirming the fix
After making your change, run the file and check for both errors and warnings. A clean run with no output to stderr means you are done. You can also verify which module type Node resolves for a specific file by checking the nearest package.json:
$ node -e "import('./app.js').then(() => console.log('ESM OK'))" --input-type=module
ESM OK
Tested on Ubuntu 24.04 with Node.js v22.22.2, npm 10.9.2.