The error message 'Cannot use import statement outside a module' is one of the most common issues faced by developers transitioning between JavaScript's two module systems: ESM (ECMAScript Modules) and CommonJS. This article will explore why this error occurs, how Node.js determines your file's module system, and how to fix the issue step-by-step.
Understanding the Error
If you've seen the error 'Cannot use import statement outside a module', it means that Node.js encountered an import statement in a file that it doesn't recognize as part of the ES module system (ESM).
JavaScript currently supports two module systems:
- CommonJS: Node.js's original module system (
require/module.exports). - ESM: The modern standard (
import/export) introduced in ECMAScript 2015 (ES6).
Node.js decides whether to treat a file as CommonJS or ESM based on:
- The file extension:
.js,.mjs,.cjs. - The type field in your
package.json: either"module"(for ESM) or"commonjs"(default for CommonJS).
If you use an import statement in a CommonJS file (determined by these rules), Node.js throws this error.
Causes of the Error
Several misconfigurations might trigger the error. Likely causes include:
- File extension mismatch:
.jsfiles default to CommonJS unless thetypefield in yourpackage.jsonis set to"module". - Incorrect type field: If
package.jsondoesn't specify"module", or explicitly sets"commonjs", all.jsfiles are treated as CommonJS. - Improper import-usage: Using
importsyntax in a file treated as CommonJS will trigger the error.
Fixing the Error: Step-by-Step
Here’s how you can resolve 'Cannot use import statement outside a module'.
steps
Explicitly Set ESM Mode:
Ensure your project uses ESM by one of the following methods:- Use the
.mjsextension for your file(s). - Set the
typefield inpackage.jsonto"module".
json{ "type": "module" }- Use the
Convert
importtorequire(if using CommonJS):
If sticking with CommonJS, replaceimportwithrequire:javascript// CommonJS const module = require('./module');instead of:
javascript// ESM (causes error in CommonJS) import module from './module';Check your Node.js version:
Ensure you’re using Node.js version 12.0.0 or newer (supports ESM). Run:bashnode --versionValidate the runtime module system:
Confirm how Node.js interprets your script using:bashnode --input-type=moduleIf you receive a syntax error, your file isn't treated as ESM.
Use .cjs or .mjs extensions strategically:
- For explicit CommonJS, use
.cjs. - For explicit ESM, use
.mjs.
- For explicit CommonJS, use
Debug dual modules with bundlers:
If you use a bundler (e.g., Webpack, Rollup), ensure the output format matches your desired module type.
Compatibility: Type Field vs Extensions
Node.js employs a nuanced decision process to resolve whether a file uses CommonJS or ESM. Here's how it decides based on the combination of type in package.json and the file extension:
comparison
Type Field: "commonjs" or Unset
.js → CommonJS
.mjs → ESM
.cjs → CommonJSType Field: "module"
.js → ESM
.mjs → ESM
.cjs → CommonJSTo avoid confusion, prefer consistent file extensions (.mjs or .cjs) and explicitly set the type field in package.json.
Decision Table: File Extension and Type Field
Here's a concise reference to Node.js's module system decision rules:
comparison
Combination Rules
.js + "type": "commonjs" → CommonJS
.js + "type": "module" → ESM
.mjs → Always ESM
.cjs → Always CommonJSTips for Avoiding Errors
Use .mjs for ESM modules.
Use .cjs for CommonJS modules.
Double-check the "type" field in package.json.Conclusion and Key Takeaways
Understanding the difference between ESM and CommonJS is critical for resolving errors like 'Cannot use import statement outside a module':
- Node.js uses file extensions and the
typefield inpackage.jsonto determine the module system. - ESM is the modern default, and using it simplifies compatibility issues across environments.
- Be explicit with your file extensions (
.mjs,.cjs) or thetypefield in your project.
By properly configuring your project to match your intended module system, you can ensure a smoother development experience.
FAQ
Why does Node default to CommonJS for .js?
Node.js historically used CommonJS as the default module system. To maintain backward compatibility, .js files default to CommonJS unless explicitly instructed otherwise via the type field in package.json.
Can I use both CommonJS and ESM in the same project?
Yes, but you must carefully manage module boundaries. You can use .cjs for CommonJS files and .mjs for ESM files. However, avoid mixing require and import within the same file.
How can I check if my file is treated as ESM or CommonJS?
Run your script with node and observe the behavior. For debugging, use:
node --input-type=moduleIf it succeeds, the file is treated as ESM.
Official reference: Node.js modules: ECMAScript modules.