Node.js Module Import

When you start writing a Node.js project, one of the first problems you encounter is how to import modules.

In Node.js, modules are reusable JavaScript files that communicate with each other through import and export.

The Node.js ecosystem mainly supports two module systems:CommonJSand ES Modules (ESM)。

Module System Specification File Extension Import Method Export Method
CommonJS Early Node.js usage .js require() module.exports / exports
ES Module (ESM) ECMAScript Standard .mjsor"type": "module" import export / export default

CommonJS Module System

CommonJS is the earliest and most widely used module system in Node.js. It uses synchronous loading, which means that when a module is loaded, it blocks program execution until the loading is complete.

Import and Export

In CommonJS, you userequire()function to import modules, and usemodule.exportsorexportsobject to export modules.

Export methods:

math.js file code:

// math.js
function add(a, b) {
  return a + b;
}

module.exports = { add };
// Or: exports.add = add;

Import methods:

Example

// app.js
const math = require('./math.js');

console.log(math.add(2, 3)); // 5

For a module to allow external access to its content, it needs to use module.exports or exports to export it:

Example

// user.js
const name = 'Alice';
const age = 30;

// Method 1: Use module.exports to export a single object or value
module.exports = {
  name: name,
  age: age,
  sayHello: () => {
    console.log(`Hello, my name is ${name}.`);
  }
};

// Method 2: Use exports to export multiple named variables
// exports is a reference to module.exports
exports.name = name;
exports.age = age;
exports.sayHello = () => {
  console.log(`Hello, my name is ${name}.`);
};

Import methods:

Example

// main.js
const user = require('./user.js');

console.log(user.name); // Output: Alice
user.sayHello(); // Output: Hello, my name is Alice.

// You can also destructure directly
const { name, age } = require('./user.js');
console.log(name); // Output: Alice

CommonJS features:

  • Synchronous loading: Suitable for server-side environments because modules are usually in the local file system and load quickly.
  • Runtime loading:require()You can call it anywhere in the code, which allows you to dynamically load modules based on conditions.
  • Caching mechanism:require()Loaded modules are cached. When imported a second time, they are read directly from the cache, avoiding repeated loading.

ES Module (ESM) Specification

ESM is the official JavaScript module standard. It uses asynchronous loading and is the first choice for browsers and modern Node.js applications.

In ESM, you useimportstatement to import modules, and useexportstatement to export modules.

Enabling ESM:To use ESM in Node.js, you need to add"type": "module", or change the file extension to.mjs。

// package.json
{
  "type": "module"
}

Exporting modules:

Example

// math.mjs
export function add(a, b) {
  return a + b;
}

export default function multiply(a, b) {
  return a * b;
}

Importing modules:

Example

// app.mjs
import multiply, { add } from './math.mjs';

console.log(add(2, 3));      // 5
console.log(multiply(2, 3)); // 6

How to enable:

  • Use file extension.mjs

  • Or add this in package.json:

    {
      "type": "module"
    }

ESM supports two export methods: named exports and default export.

Example

// user.mjs

// Named export
export const name = 'Bob';
export const age = 25;

// Default export
const sayHello = () => {
  console.log(`Hello, my name is ${name}.`);
};
export default sayHello;

Import methods:

Example

// main.mjs

// Import named export
import { name, age } from './user.mjs';
console.log(name); // Output: Bob

// Import default export
import sayHello from './user.mjs';
sayHello(); // Output: Hello, my name is Bob.

// Import named and default exports together
import sayHello, { name } from './user.mjs';
console.log(name);
sayHello();

// Import all named exports as properties of an object
import * as user from './user.mjs';
console.log(user.name);
user.default(); // The default export will be the default property

ESM features:

  • Asynchronous loading: It is asynchronous by default and does not block the main thread, making it more suitable for browser environments, but in Node.js it usually behaves as synchronous loading.
  • Static analysis:importandexportstatements can determine module dependencies before code execution, allowing tools (such as Webpack, Vite) to perform better optimizations (such asTree Shaking)。
  • Strict mode: ESM modules run in strict mode by default.

Differences Between CommonJS and ESM

Item CommonJS ESM
Syntax require / module.exports import / export
Loading mechanism Synchronous loading at runtime Static loading at compile time
Default support Supported by default in Node.js Need.mjsor"type": "module"
Suitable scenarios Backend scripts, legacy projects Modern frontend and backend projects, Tree-shaking
Can they be mixed? Cannot be mixed directly (requires additional configuration) Cannot be mixed directly (requires additional configuration)

Mixed Usage

Node.js supports coexistence of both module systems in newer versions. You can use CommonJS and ESM together in the same project, but you need to note the following:

  • ESM cannot directly userequire()andmodule.exports。
  • CommonJS cannot directly useimportandexport。
  • If you want to import a CommonJS module in ESM, you can directly useimportstatement, and ESM will treat it as a default export.

    // commonjs_module.js
    module.exports = { data: 'hello' };
    
    // esm_module.mjs
    import commonModule from './commonjs_module.js';
    console.log(commonModule.data); // 输出: hello
    
  • If you want to import an ESM module in CommonJS, you need to use dynamicimport()function.

    // esm_module.mjs
    export const name = 'Bob';
    
    // commonjs_module.js
    async function loadESM() {
      const { name } = await import('./esm_module.mjs');
      console.log(name);
    }
    loadESM();
    

Best Practice Suggestions

For new projects,it is strongly recommended to use ES Modules (ESM). It is not only the official standard for JavaScript, but also has better compatibility with modern frontend toolchains (such as Vite, Next.js), and can fully utilize optimization techniques like Tree Shaking to reduce the bundled code size.

If you are maintaining an old CommonJS project and do not need ESM features, you can continue using CommonJS. However, if you need to introduce new dependencies or take advantage of ESM's new features, you can consider migrating gradually or using mixed mode as a transition.

Other Extensions