Cannot use import statement outside a module in Node.js

Updated Apr 18, 2024#node#es-modules#how-to

ES Modules are a new way of writing JavaScript code that use the import and export statements to manage dependencies between files. ES Modules are supported by most modern browsers and have some advantages over the traditional CommonJS module system that Node.js uses by default.

One common error with ES modules in Node.js is the “SyntaxError: Cannot use import statement outside a module”. This error means that you are trying to use the import statement in a file that is treated as a CommonJS module by Node.js. There are a few ways to fix this error, depending on your preferences and project setup.

  • Using Node.js ES modules native support
  • Using Babel with Node.js
  • Using TypeScript with Node.js

Babel and TypeScript help transpile code to a version that is compatible with older versions of Node.js, providing better support for legacy systems. On the other hand, native module support in Node.js can offer performance advantages and simpler setup, but may require additional effort to ensure cross-version compatibility.

Using Node.js ES modules native support

The --experimental-modules flag was first introduced in Node.js version 8.5.0, Node.js v12 shipped a new implementation of --experimental-modules that replaced the old one. However, this flag was not dropped until Node.js v13.2.0, which became the first version to support ES modules without any flags. Therefore, if you want to use ES modules in Node.js without any flags, you need to use Node.js v13.2.0 or higher.

Latest Node.js fully supports ES modules as they are currently specified and provides interoperability between them and its original module format, CommonJS.

Node.js will treat the following as ES modules:

  • Files with an .mjs extension.
  • Files with a .js extension when the nearest parent package.json file contains a top-level “type” field with a value of “module”.
  • Strings passed in as an argument to --eval, or piped to node via STDIN, with the flag --input-type=module.

Outside of those cases, Node.js will use the CommonJS modules.

If you want to keep the .js file extension in your project, you must use “type” in package.json file at the top level:

{
  // ...
  "type": "module",
}
  • A package.json “type” value of “module” tells Node.js to interpret .js files within that package as using ES module syntax.
  • Files ending with .mjs are always loaded as ES modules regardless of the nearest parent package.json.
  • Files ending with .cjs are always loaded as CommonJS regardless of the nearest parent package.json.

Using Babel with Node.js

To use Babel with Node.js, you need to install some packages and create some configuration files in your project. Here are the basic steps to get started:

  1. Install @babel/cli and @babel/core packages as development dependencies:
npm install --save-dev @babel/cli @babel/core
  1. Install @babel/preset-env package as a development dependency. This is a preset that enables you to use the latest JavaScript features without worrying about compatibility issues.
npm install --save-dev @babel/preset-env
  1. Create a .babelrc file in your project root and add the following content:
{
  "presets": ["@babel/preset-env"]
}

This tells Babel to use the @babel/preset-env preset when transpiling your code.

  1. To transpile your code, you can use the babel command with the —out-dir option to specify the output directory. For example, if you have your source code in a folder called src, you can run:
npx babel src --out-dir lib

This will transpile all the files in the src folder and output them to the lib folder.

  1. To run your transpiled code with Node.js, you can use the node command with the path to the output file. For example, if you have an entry point file called index.js, you can run:
node lib/index.js

This will run your transpiled code with Node.js.

You can also use scripts in your package.json file to simplify these commands. For example, you can add:

{
  "scripts": {
    "build": "babel src --out-dir lib",
    "start": "node lib/index.js"
  }
}

Then you can run:

npm run build
npm start

To transpile and run your code with Node.js.

Using TypeScript with Node.js

To use TypeScript with Node.js, you need to install some packages and create some configuration files in your project. Here are the basic steps to get started:

  1. Install typescript package as a development dependency:
npm install --save-dev typescript
  1. Create a tsconfig.json file in your project root and run the following command to initialize it:
npx tsc --init

This tells TypeScript to create a default configuration file for your project.

  1. Edit the tsconfig.json file and add or modify some options according to your preferences. For example, you can change the target option to specify the output JavaScript version, or the outDir option to specify the output directory. You can also enable or disable some features like strict mode or sourceMap generation.

  2. To transpile your TypeScript code to JavaScript code, you can use the tsc command with the —build option and the path to your source file. For example, if you have an entry point file called index.ts, you can run:

npx tsc --build index.ts

This will transpile your TypeScript code and output it to the directory specified by the outDir option in your tsconfig.json file.

  1. To run your transpiled code with Node.js, you can use the node command with the path to the output file. For example, if you have an entry point file called index.ts, and your output directory is dist, you can run:
node dist/index.js

This will run your transpiled code with Node.js.

You can also use scripts in your package.json file to simplify these commands. For example, you can add:

{
  "scripts": {
    "build": "tsc --build index.ts",
    "start": "node dist/index.js"
  }
}

Then you can run:

npm run build
npm start

To transpile and run your code with Node.js.