# Use import Instead of require

![Use import Instead of require](https://raw.githubusercontent.com/mateenkiani/milddev-resources/main/images/1752168729946_1752168729743.webp)

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](https://milddev.com/how-is-nodejs-asynchronous-when-javascript-is-single-threaded) 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:

   ```json
   {
     "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](https://milddev.com/how-to-create-a-nodejs-project-in-vs-code) 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:

| Feature                | CommonJS (`require`)    | ES Modules (`import`)    |
|------------------------|-------------------------|--------------------------|
| Syntax location        | Inline                  | Top of file              |
| Dynamic loading        | `require()` works anywhere | Use `import()` function   |
| Named imports          | Destructure after load  | Native named imports      |
| File extension support | `.js`, `.cjs`           | `.mjs`, `.js` with config |

Dynamic `import()` lets you load modules at runtime:

```js
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.

