Home DevOps & Cloud Security Software Engineering AI & Machine Learning Web Development Developer Tools Programming Languages Databases Architecture & Systems Design Emerging Tech About
Programming Languages

Node.js: Cannot use import statement outside a module

NanoTech Insight
NanoTech Insight
2026-10-27
How this article was made: drafted with AI assistance and grounded in the sources linked at the end of the article. Spotted an error? Let us know.
Terminal showing Node.js module error

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:

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

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.

References

nodejs javascript esm commonjs modules import
NanoTech Insight
Published by
NanoTech Insight
Independent technology site

This article was drafted with AI assistance and grounded in the references linked above. Technology changes quickly, so please verify details against official documentation before relying on them in production.

Related Articles

Python asyncio vs threading vs multiprocessing
2026-10-23
git push rejected non-fast-forward: Causes and Fixes
2026-10-20
Python list comprehension vs generator: when to use which
2026-10-16
json.decoder.JSONDecodeError: Expecting value: line 1 column 1
2026-10-13
← Back to Home