Skip to content

ES Modules in Node.js: package.json type field

When working with Node.js projects, you may encounter the error: Error [ERR_REQUIRE_ESM]: Must use import to load ES Module. This typically occurs when your project configuration conflicts with JavaScript module systems. Here's what you need to know about the "type": "module" field in package.json and how to resolve these issues.

Understanding the package.json "type" field

The "type" field in package.json determines how Node.js interprets .js files in your project:

  • Default behavior: Without a "type" field or with "type": "commonjs", Node.js treats .js files as CommonJS modules (using require() and module.exports)
  • ES Module mode: With "type": "module", Node.js treats .js files as ES modules (using import and export syntax)
json
{
  "name": "your-project",
  "type": "module",
  "scripts": {
    "start": "node index.js"
  }
}

The Problem: Module System Conflicts

The error message you encountered indicates a mismatch between your module systems:

javascript
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module
require() of ES modules is not supported.

This happens when:

  1. Your package.json has "type": "module"
  2. Your code uses require() instead of import
  3. You're trying to import an ES module file using CommonJS syntax

Solutions

Solution 1: Consistent Module Usage

Ensure your code matches your package.json configuration:

For ES Modules ("type": "module):

javascript
// Correct: ES Module syntax
import express from 'express';
export default myFunction;

For CommonJS (no type field or "type": "commonjs"):

javascript
// Correct: CommonJS syntax
const express = require('express');
module.exports = myFunction;

Solution 2: File Extension Approaches

Node.js supports different file extensions for different module types:

  • .js - Depends on package.json "type" field
  • .mjs - Always treated as ES module
  • .cjs - Always treated as CommonJS module

You can rename files to enforce module type regardless of package.json:

bash
# ES Module files
mv nuxt.config.js nuxt.config.mjs

# CommonJS files  
mv config.js config.cjs

Solution 3: Modern Node.js Features (v20.10.0+)

Recent Node.js versions offer additional options:

bash
# Automatic module detection
node --experimental-detect-module index.js

# Set default module type
node --experimental-default-type="module" index.js

Add these to your package.json scripts for convenience:

json
{
  "scripts": {
    "start": "node --experimental-detect-module index.js",
    "dev": "node --experimental-default-type=\"module\" index.js"
  }
}

Solution 4: Runtime Module Type Selection

For special cases like CI/CD pipelines, you can specify module type at execution:

bash
# Execute as ES module without package.json configuration
node --input-type=module -e "import { myFunc } from './module.js'; myFunc();"

Best Practices

  1. Be consistent - Choose one module system for your project
  2. Update Node.js - Use the latest LTS version for best ES module support
  3. Use explicit extensions - Consider .mjs/.cjs for clarity in mixed projects
  4. Check dependencies - Ensure your dependencies support your chosen module system

WARNING

Removing "type": "module" may solve immediate errors but could break other parts of your code that use ES module syntax. Always check your entire codebase before making this change.

TIP

As of Node.js v16+ (LTS), ES module support is stable and well-tested. Consider migrating to ES modules for future-proofing your code.

Conclusion

The "type": "module" field enables ES module syntax in Node.js. Whether to keep or remove it depends on your project's needs:

  • Keep it if you want to use modern import/export syntax
  • Remove it if you prefer CommonJS require/module.exports syntax
  • Use file extensions (.mjs/.cjs) for mixed codebases
  • Leverage Node.js flags for flexibility in newer versions

Choose the approach that best fits your project requirements and team preferences while ensuring consistency throughout your codebase.