Is it OK to Mix Import & Require Statement in Node?

In Node.js, it’s generally recommended not to mix import and require statements within the same file because they represent different module systems and have different behaviors and syntaxes. Here are some key points to consider when deciding between import and require:

Differences in Syntax and Behavior

  • import/export: This syntax is part of the ECMAScript modules (ESM) specification. import and export are static and enable various optimizations by JavaScript engines. They must be at the top level of your files (not nested inside functions or conditions) and are processed before the code executes.
  • require/module.exports: This is the CommonJS (CJS) module system used traditionally in Node.js. It’s dynamic, meaning you can call require() under any circumstances, such as within functions, conditionals, or at any point in your script.

Compatibility and Environment

  • Node.js Version: Node.js has supported ESM from version 12 onwards, but it became stable and generally more usable without experimental flags from version 14 onwards.
  • File Extensions: Node.js uses the .mjs extension for ECMAScript modules and .cjs for CommonJS modules when it needs to distinguish between them, especially if you’re enabling ESM in a project that uses "type": "module" in the package.json.
  • Mixing Modules:
    • If your project configuration uses "type": "module" in package.json, Node.js treats .js files as ESM by default. Here, using require in .js files will throw an error, but you can still use require in .cjs files.
    • If your project does not use "type": "module", Node.js treats .js files as CommonJS by default, and using import in .js files will not work unless you use them with .mjs files or run Node.js with specific flags to enable ESM.

Best Practices

  • Consistency: Choose one module system per project or per package boundary when possible. This consistency helps in maintaining the code and avoiding runtime issues.
  • Migration: If migrating from CommonJS to ESM, do it at the level of the entire project or at least on a per-package basis, rather than mixing within a single file.
  • Third-party Modules: Be aware that some npm packages might only offer CommonJS modules or only ESM. You may need to check the documentation on how to properly import these packages into your project.

Example of Importing CommonJS into ESM

If you need to use a CommonJS module in an ESM file, you can do it using dynamic imports:

// Asynchronously importing a CommonJS module in an ESM file
import('some-commonjs-package').then((pkg) => {
  console.log(pkg);
});

This approach uses a dynamic import() which returns a promise, and it’s the recommended way to load CommonJS modules into ESM code.

Conclusion

While technically feasible in some scenarios, mixing import and require in the same project or file can lead to confusion and errors, particularly around the module resolution and build processes. It’s best to stick to one module system within a single project or component to ensure clarity and maintain compatibility across different environments.