How to Resolve the “Cannot Use Import Statement Outside a Module” Error

You’re happily writing JavaScript (or TypeScript), you type:

import { something } from './myModule.js'

SyntaxError: Cannot use import statement outside a module

Ugh. What just happened, Why does JavaScript suddenly refuse your clean import line

I’ll walk you through exactly why that error happens, when and where it applies (browser vs Node.js vs testing), and how to fix it in real projects. I’ll also compare what current blogs say (where they fall short) and share new tips you may not see elsewhere. By the end, you’ll confidently fix this error and avoid it in future.

What the Error

When JavaScript says “Cannot use import statement outside a module”, it’s telling you:

“Hey, I see you used an import keyword here, but I’m not treating this file (or execution context) as an ES module. So I can’t process import. I expected a plain script or CommonJS instead.”

In more concrete terms:

  • ES modules are JavaScript files where you use import / export.
  • But not every JS file is automatically a module. Sometimes environments assume “plain script” or CommonJS modules.
  • If your file isn’t recognized as a module, JavaScript (in browser or Node) rejects the import syntax and raises that error.

Why It Happen in Browsers

Script tags need type="module"

In HTML, when you include JavaScript via <script>, by default it’s a “regular script.” Regular scripts do not support import/export. To tell the browser “Hey, this is a module,” you use:

<script type="module" src="main.js"></script>

Without type="module", the browser treats it as plain JS and will throw the error.

Server and MIME type

Even if you set type="module", your server must serve the .js file with the right MIME type (text/javascript). Some servers mistakenly send wrong types (like text/plain), which breaks module loading.

Relative paths, file extensions

Imports in modules must often include the correct path and extension. For example:

import { foo } from './module.js'

If you wrote import { foo } from './module' (without .js) or used wrong relative path, the browser may fail to resolve or treat it incorrectly. Many how-to blogs mention this briefly but don’t stress the “always include extension” rule. (I’ll show a deeper example later.)

No bundler means module isolation

In large apps, you usually bundle your modules (Webpack, Rollup, etc.). Bundlers understand your import statements and combine files into something the browser can load. If you skip bundling or misconfigure it, your raw module code might reach the browser untransformed, triggering this error.

Why It Happen in Node.js

Node.js has its own “default module” rules, and things get confusing because Node historically used CommonJS (with require) and now supports ES modules side by side. Many blogs cover the basics (package "type" or .mjs), but I’ll go deeper, including tricky cases.

CommonJS vs. ES Module in Node

  • By default, Node treats .js files as CommonJS, which uses require, module.exports, etc.
  • ES modules (import/export) need special enabling.
  • Node recognizes .mjs files as ES modules automatically (no special config).
  • Or, you can set "type": "module" in your package.json, telling Node to interpret .js files as ES modules.

So, if you write import in a .js in a project where Node assumes CommonJS, you’ll get the “Cannot use import statement outside a module” error.

Mix ES and CommonJS in One Project

Sometimes you want to mix both. E.g., some third-party library is CommonJS, or you have legacy code. In that case:

  • Use .cjs for files intended as CommonJS.
  • Use .mjs for ES modules explicitly.
  • Or use import() dynamic import to import ES modules from CommonJS context (or vice versa).
  • Or use Babel or a transpiler to convert ES modules into CommonJS.

Node version and experimental modules

Older Node versions (before v13.2.0) required using the --experimental-modules flag to enable ES module support. Newer Node versions have better built-in support. If you’re stuck on an old version, that flag might be needed.

Using type: module in package.json

Example:

{
  "name": "my-app",
  "version": "1.0.0",
  "type": "module"
}

With that, Node treats .js files as ES modules, so import works. But remember: then any file using CommonJS (require) must instead use .cjs extension or fallback.

Other Cases Testing, Bundlers, Mixed Code

Jest / Testing Environments

If you write tests and use import, Jest might fail with the same “Cannot use import statement outside a module” unless configured to handle ES modules. You might need:

  • Use babel-jest to transpile importrequire.
  • Add "type": "module" in package.json used in the test environment.
  • Configure Jest’s transform or transformIgnorePatterns so that your ES modules (or node_modules using ES modules) get transpiled.

Many blog posts skip this section, but in real projects this is often where the error surfaces (in your tests).

Bundlers and Transpilers

If you’re using Webpack, Rollup, Babel, or similar, you must ensure your bundling pipeline understands ES modules:

  • Babel preset @babel/preset-env must be configured to allow module syntax or transform to target environment modules.
  • Webpack must not accidentally treat your module as “external” or ignore it.
  • For library authors, bundling target matters (UMD, ESM, CJS).
  • If a third-party library ships in ES module form and your bundler isn’t set to handle it, you might see this error.

Dynamic Import

Sometimes, you can avoid the static import by using import() dynamically, especially in mixed module environments or lazy loading. This may bypass the “outside module” check because import() is treated differently in some runtimes.

Fixes The Code

Now let’s get hands dirty. Below are concrete steps and example code to fix the error depending on your scenario.

In Browser / Frontend Projects

  1. Use type="module" on your script tags:
<script type="module" src="index.js"></script>
  1. Always use correct paths and extensions:
// Good
import { greet } from './greet.js';

// Bad (might break)
import { greet } from './greet';
  1. Use an HTTP server (don’t just open .html file via file://) because module import may be blocked by CORS or not allowed locally.
  2. If your browser bundle is using older bundlers, ensure they handle ES modules. Use tools like Webpack, Rollup, or Parcel, and configure properly.

In Node.js Projects

  1. Decide: use ES modules or CommonJS consistently.
  2. If ES module:
    • Set "type": "module" in package.json, or
    • Rename your module files to .mjs.
  3. If using CommonJS:
    • Replace import with require: const { foo } = require('./foo.js');
    • Use module.exports instead of export.
  4. If you have a mix, e.g. one file is ES module and another is CommonJS:
    • Name them .mjs and .cjs appropriately, or
    • Use dynamic import() in CommonJS file (which returns a Promise).
    • Or use a transpiler (Babel) to unify.
  5. For older Node versions, run your script with:
node --experimental-modules yourFile.mjs

In Testing (Jest etc.)

  1. Install Babel-related packages:
npm install --save-dev babel-jest @babel/core @babel/preset-env
  1. Create babel.config.js:
module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }],
  ],
};
  1. In Jest config (e.g. jest.config.js), set:
module.exports = {
  transform: {
    '^.+\\.jsx?$': 'babel-jest'
  },
  // if needed:
  transformIgnorePatterns: ['/node_modules/(?!(some-esm-lib)/)']
};
  1. Optionally, set "type": "module" in package.json used in test environment.

Summary

The “Cannot Use Import Statement Outside a Module” error is a sign that your JavaScript file isn’t being treated as an ES module. The fix always involves aligning your environment (browser, Node, bundler, testing) so it knows to use ES modules where import/export is allowed.

Related blog posts