Skip to content

Import and Export Styles in Node.js

Let’s dive into the different styles of import and export in Node.js! Node.js supports two primary module systems: CommonJS (the traditional Node.js module system) and ES Modules (ESM) (the modern JavaScript standard). Each has its own syntax and quirks, so I’ll break them down clearly with examples.


1. CommonJS (CJS)

CommonJS is the original module system in Node.js, using require() for imports and module.exports or exports for exports. It’s synchronous and still widely used, especially in older projects.

Exporting in CommonJS

  • Named Exports: You can export multiple items using the exports object.
    javascript
    // math.js
    exports.add = (a, b) => a + b;
    exports.subtract = (a, b) => a - b;
  • Default Export: Use module.exports to export a single value or object.
    javascript
    // greet.js
    module.exports = (name) => `Hello, ${name}!`;
  • Mixing Both: You can combine named and default exports, but be cautious—module.exports overrides exports if redefined.
    javascript
    // mixed.js
    exports.foo = 'bar';
    module.exports = { baz: 'qux' }; // Overrides exports.foo

Importing in CommonJS

  • Named Imports: Access named exports via require().
    javascript
    const { add, subtract } = require('./math');
    console.log(add(2, 3)); // 5
  • Default Import: Assign the entire export to a variable.
    javascript
    const greet = require('./greet');
    console.log(greet('Alice')); // "Hello, Alice!"
  • Dynamic Path: You can use variables with require().
    javascript
    const moduleName = './math';
    const { add } = require(moduleName);

Key Notes

  • CommonJS is the default in Node.js unless "type": "module" is set in package.json.
  • File extensions (e.g., .js) are optional in require() paths.

2. ES Modules (ESM)

ESM is the standardized JavaScript module system, introduced in Node.js v12+ and fully supported since v14. It uses import and export keywords and is asynchronous by nature.

Enabling ESM

  • Add "type": "module" in package.json.
  • Use the .mjs file extension (optional if "type": "module" is set).
  • Without these, Node.js defaults to CommonJS.

Exporting in ESM

  • Named Exports: Export specific items with the export keyword.
    javascript
    // math.mjs
    export const add = (a, b) => a + b;
    export const subtract = (a, b) => a - b;
  • Default Export: Export a single value with export default.
    javascript
    // greet.mjs
    export default (name) => `Hello, ${name}!`;
  • Mixed Exports: You can combine named and default exports.
    javascript
    // mixed.mjs
    export const foo = 'bar';
    export default { baz: 'qux' };

Importing in ESM

  • Named Imports: Use curly braces to import specific items.
    javascript
    import { add, subtract } from './math.mjs';
    console.log(add(2, 3)); // 5
  • Default Import: Assign the default export to any variable name.
    javascript
    import greet from './greet.mjs';
    console.log(greet('Bob')); // "Hello, Bob!"
  • Import All (Namespace Import): Import everything as an object.
    javascript
    import * as math from './math.mjs';
    console.log(math.add(2, 3)); // 5
  • Dynamic Import: Use import() for asynchronous loading (returns a Promise).
    javascript
    const { add } = await import('./math.mjs');
    console.log(add(2, 3)); // 5

Key Notes

  • File extensions (e.g., .mjs or .js) are required in ESM paths unless using a module resolver.
  • ESM is static (analyzed at parse time), so import statements must be top-level and can’t use dynamic variables directly (use import() instead).

3. Differences Between CommonJS and ESM

FeatureCommonJSESM
Syntaxrequire(), module.exportsimport, export
LoadingSynchronousAsynchronous
File ExtensionsOptionalRequired (in Node.js)
Dynamic Importrequire(variable)import() (Promise)
Top-Level AwaitNot supportedSupported (Node.js 14+)
Default in Node.jsYes (unless overridden)No (needs "type": "module")

4. Interoperability

  • CJS in ESM: You can import CommonJS modules in ESM using import.
    javascript
    import myModule from './myCommonJsModule.js'; // Works if it uses module.exports
  • ESM in CJS: Use dynamic import() since require() can’t handle ESM natively.
    javascript
    (async () => {
      const { add } = await import('./math.mjs');
      console.log(add(2, 3)); // 5
    })();

5. Practical Tips

  • Choosing a System: Use ESM for new projects (modern, standardized) and CommonJS for legacy compatibility.
  • Mixing Systems: Be cautious—test thoroughly, as edge cases can trip you up.
  • Node.js Version: ESM is stable in v14+, so ensure your runtime supports it if you go that route.

Credit @Wayne19980