Troubleshooting & Comparisons

Resolving 'Cannot use import statement outside a module'

Learn how to resolve 'Cannot use import statement outside a module' and understand ESM vs CommonJS module systems.

5 min read

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:

  1. CommonJS: Node.js's original module system (require/module.exports).
  2. 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: .js files default to CommonJS unless the type field in your package.json is set to "module".
  • Incorrect type field: If package.json doesn't specify "module", or explicitly sets "commonjs", all .js files are treated as CommonJS.
  • Improper import-usage: Using import syntax 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

  1. Explicitly Set ESM Mode:
    Ensure your project uses ESM by one of the following methods:

    • Use the .mjs extension for your file(s).
    • Set the type field in package.json to "module".
    json
    {
      "type": "module"
    }
  2. Convert import to require (if using CommonJS):
    If sticking with CommonJS, replace import with require:

    javascript
    // CommonJS
    const module = require('./module');

    instead of:

    javascript
    // ESM (causes error in CommonJS)
    import module from './module';
  3. Check your Node.js version:
    Ensure you’re using Node.js version 12.0.0 or newer (supports ESM). Run:

    bash
    node --version
  4. Validate the runtime module system:
    Confirm how Node.js interprets your script using:

    bash
    node --input-type=module

    If you receive a syntax error, your file isn't treated as ESM.

  5. Use .cjs or .mjs extensions strategically:

    • For explicit CommonJS, use .cjs.
    • For explicit ESM, use .mjs.
  6. 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  → CommonJS

Type Field: "module"

.js   → ESM
.mjs  → ESM
.cjs  → CommonJS

To 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 CommonJS

Tips 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 type field in package.json to 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 the type field 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:

bash
node --input-type=module

If it succeeds, the file is treated as ESM.


Official reference: Node.js modules: ECMAScript modules.