Use import Instead of require

Mateen Kiani

Mateen Kiani

Published on Thu Jul 10 2025·4 min read

use-import-instead-of-require

Node.js has made server-side JavaScript a breeze, but the way we bring code into a file—modules—has evolved over time. While CommonJS and its require() syntax served us well, ES Modules (import/export) are the modern standard. Yet many developers still mix both styles or stick to require() out of habit. Ever wondered why mixing require() and import sometimes leads to odd errors or broken builds?

Switching fully to ES Modules and import solves those headaches. Understanding how to enable ESM in Node.js, migrate existing code, and handle interoperability lets you write cleaner, future-proof code. Let’s dive into why import matters and how it benefits your next project.

Why ESM Matters

ES Modules (ESM) are the official JavaScript module standard. Browsers and modern build tools embrace them, giving you:

  • Static analysis: Tools can tree-shake unused exports at build time.
  • Cleaner syntax: import statements sit at the top and clearly show dependencies.
  • Future compatibility: Align your server code with browser code.

Node.js supported CommonJS first, but recent releases back ESM natively. By declaring modules as ESM, you avoid runtime flags and Babel transpilation. You also tap into features like import.meta.url and top-level await. If you haven’t already, read about Node.js’s event loop and Node.js asynchronous nature to see how modules load in a non-blocking system.

Tip: Pick one module system per project. Mixing can lead to confusing loader errors.

Enable ES Modules

To run ESM in Node.js:

  1. In your package.json, set:

    {
    "type": "module"
    }
  2. Rename files to .mjs or keep .js if type is set.
  3. Use node file.js as usual.

If you need compatibility, you can also:

  • Use the --experimental-modules flag on older Node versions.
  • Mix .cjs and .mjs extensions to separate CommonJS and ESM files.

For a quick start, see this Node.js project setup guide in VS Code.

Migrate Your Code

When moving an existing codebase:

  1. Update imports: ```js // Old CommonJS const fs = require('fs');

    // New ESM import fs from 'fs'; ```

  2. Handle default vs named exports:
    • CommonJS modules often export an object. In ESM, you may need import pkg from 'pkg'.
    • For named exports, use export const x = 1; then import { x } from './file.js'.
  3. Check third-party libraries: Some packages still ship only CommonJS. You can:
    • Import using dynamic import().
    • Keep certain files as .cjs and load with require().

Tip: Run your test suite after each batch of changes to catch missing exports early.

Interop Between Worlds

Sometimes you need both systems. Here’s a quick comparison:

FeatureCommonJS (require)ES Modules (import)
Syntax locationInlineTop of file
Dynamic loadingrequire() works anywhereUse import() function
Named importsDestructure after loadNative named imports
File extension support.js, .cjs.mjs, .js with config

Dynamic import() lets you load modules at runtime:

async function loadConfig() {
const config = await import('./config.js');
return config.default;
}

Quote: “Interop is possible, but clarity wins. Strive to convert entire modules when you can.”

Performance Tips

Switching to import rarely affects raw performance. But static import lets build tools optimize your bundle:

  • Tree-shaking: Dead code elimination with Rollup or webpack.
  • Faster startup: Less parsing overhead if you only import what you need.

Local tips:

  • Group related imports to help bundlers: js import { readFile, writeFile } from 'fs/promises';
  • Use top-level await in ESM for sequential startup tasks: js const config = await import('./config.js');

Tip: Benchmark critical paths using simple timers before and after migration.

Best Practices

  • Always prefer named exports where possible. It makes code self-documenting.
  • Keep your package.json type field consistent across services.
  • Automate migrations with codemods or simple regex scripts.
  • Lint for mixed syntax using ESLint rules no-commonjs or plugins.

Conclusion

ES Modules in Node.js are no longer experimental—they’re the future of modular JavaScript. Moving from require() to import helps you align with browser code, enable advanced build optimizations, and simplify dependency management. By updating your package.json, renaming extensions, and migrating exports step by step, you can avoid downtime and buggy behavior. Remember to test thoroughly and keep an eye on interoperability when third-party packages haven’t caught up.

Takeaway: Commit to one module system per project, lean on static import for clarity, and embrace the modern JavaScript ecosystem with confidence.


Mateen Kiani
Mateen Kiani
kiani.mateen012@gmail.com
I am a passionate Full stack developer with around 3 years of experience in MERN stack development and 1 year experience in blockchain application development. I have completed several projects in MERN stack, Nextjs and blockchain, including some NFT marketplaces. I have vast experience in Node js, Express, React and Redux.