Running node index.js gives SyntaxError: Cannot use import statement outside a module. Other times I get ReferenceError: require is not defined in ES module scope. How do ESM and CommonJS fit together?
DEV3 Developer Forum
How do I fix 'Cannot use import statement outside a module' and 'require is not defined' in Node.js?
Every post is reviewed first. Usually reviewed within 24 hours.
1 reply
Node supports two module systems and decides per file.
ESM (import/export)
Used when the file ends in .mjs, or .js and the nearest package.json has "type": "module".
CommonJS (require/module.exports)
Used for .cjs, or .js when "type" is missing or "commonjs".
Fixing "Cannot use import statement outside a module"
You wrote ESM syntax in a CommonJS file. Either:
{ "type": "module" }
in package.json, or rename to .mjs, or switch to require.
Fixing "require is not defined in ES module scope"
You are in ESM. Replace:
import fs from 'node:fs';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url); // only if you really need require
Also, __dirname and __filename do not exist in ESM:
import { fileURLToPath } from 'node:url';
import path from 'node:path';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
Recent Node versions also provide import.meta.dirname and import.meta.filename.
ESM rules
- Relative imports need the file extension:
import x from './x.js'. - JSON needs an import attribute:
import data from './data.json' with { type: 'json' }. - Top-level
awaitworks in ESM. - ESM can import CommonJS; importing ESM from CommonJS is possible via
await import(), and recent Node versions also allowrequire()of synchronous ESM (check your version's docs).
TypeScript
Set "module": "nodenext" (or esnext with a bundler) and keep "type": "module" consistent. Tools like tsx run both.
Pitfall: mixing "type": "module" with an old Jest/ts-node setup is a frequent source of this error; configure the tool for ESM or use Vitest.