Chapter 13: Module Basics
1. What is a “module” in Node.js?
A module is just a file that contains some code that you want to reuse in other files.
The most common things you put in modules:
- Utility functions
- Classes / models
- Configuration values
- Route handlers
- Database helpers
- Middleware
- Services / business logic
The big idea:
Instead of putting 2000 lines in one file, you split your code into many small, focused files (modules) and import only what you need.
2. Two completely different module systems in Node.js (very important)
| System | Syntax | File extension | package.json field | Status in 2025–2026 | Recommendation today |
|---|---|---|---|---|---|
| CommonJS | require() / module.exports | .js | (no special field) | Still very widely used | Legacy / old projects |
| ES Modules (ESM) | import / export | .js or .mjs | “type”: “module” | The modern standard | New code → use this |
2025–2026 reality check:
- Almost all new libraries are published as ESM (or dual)
- Most new projects start with ESM
- Many old projects still use CommonJS
- You will meet both in real life
3. Let’s see both systems with the exact same example
We’ll create a small utility module that formats dates and exports two functions.
Folder structure
|
0 1 2 3 4 5 6 7 8 9 10 |
project/ ├── utils/ │ └── date-utils.js ← our module ├── index.js ← main file └── package.json |
A. CommonJS version (old style – still very common)
utils/date-utils.js
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
function formatDate(date) { return date.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' }); } function getCurrentDateTime() { return new Date().toLocaleString('en-IN'); } // This is how you export in CommonJS module.exports = { formatDate, getCurrentDateTime }; |
index.js
|
0 1 2 3 4 5 6 7 8 9 |
const { formatDate, getCurrentDateTime } = require('./utils/date-utils'); console.log("Today:", getCurrentDateTime()); console.log("Formatted:", formatDate(new Date())); |
Run:
|
0 1 2 3 4 5 6 |
node index.js |
B. ES Modules version (modern style – recommended for new code)
First — add this to package.json (very important!)
|
0 1 2 3 4 5 6 7 8 9 10 |
{ "name": "my-project", "type": "module", // ← this line enables ESM ... } |
utils/date-utils.js (same file, different syntax)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
export function formatDate(date) { return date.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' }); } export function getCurrentDateTime() { return new Date().toLocaleString('en-IN'); } // You can also do default export (one main thing) export default { formatDate, getCurrentDateTime }; |
index.js (modern import syntax)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Option 1: named imports (most common) import { formatDate, getCurrentDateTime } from './utils/date-utils.js'; // Option 2: import everything as object // import dateUtils from './utils/date-utils.js'; console.log("Today:", getCurrentDateTime()); console.log("Formatted:", formatDate(new Date())); |
Run:
|
0 1 2 3 4 5 6 |
node index.js |
Important note: When using ESM → you usually need to write the .js extension in imports (./utils/date-utils.js not just ./utils/date-utils)
4. Comparison table – CommonJS vs ESM (what changes)
| Feature | CommonJS | ES Modules (ESM) | Winner 2026 |
|---|---|---|---|
| Syntax | require(), module.exports | import, export | ESM |
| File extension required? | No | Usually yes (.js) | — |
| package.json required field | — | “type”: “module” | — |
| Top-level await | Not allowed | Allowed | ESM |
| Circular dependencies | Works (sometimes confusing) | Works, but stricter | — |
| Tree-shaking support | Weak | Excellent (modern bundlers) | ESM |
| Dynamic import | require() anywhere | await import() only in async context | CommonJS |
| Ecosystem momentum 2025–2026 | Declining (but huge legacy) | Growing very fast | ESM |
5. Most common ways people export & import (real patterns)
Named exports (most popular in modern code)
|
0 1 2 3 4 5 6 7 8 9 |
// user-service.js export function findUserById(id) { ... } export function createUser(data) { ... } export const ROLES = { ADMIN: 'admin', USER: 'user' }; |
|
0 1 2 3 4 5 6 7 |
// usage import { findUserById, ROLES } from './user-service.js'; |
Default export (one main thing per file)
|
0 1 2 3 4 5 6 7 8 9 10 |
// logger.js export default class Logger { info(msg) { console.log(`[INFO] ${msg}`); } error(msg) { console.error(`[ERROR] ${msg}`); } } |
|
0 1 2 3 4 5 6 7 |
import Logger from './logger.js'; const log = new Logger(); |
Mixed style (very common)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
export const PI = 3.14159; export function add(a, b) { return a + b; } export default class Calculator { multiply(a, b) { return a * b; } } |
|
0 1 2 3 4 5 6 |
import Calculator, { PI, add } from './math.js'; |
6. Quick reference – What you should do in 2026
| Project type | Module system recommendation | How to start |
|---|---|---|
| Brand new project / learning | ESM | Add “type”: “module” in package.json |
| Maintaining old Express app | CommonJS (usually) | Keep require / module.exports |
| Publishing an npm package | ESM (with dual support if needed) | Use exports field in package.json |
| Using modern frameworks (Fastify, Hono, NestJS) | Almost always ESM | They default to ESM |
| Using Prisma, Drizzle, Zod, etc. | ESM | Most new libs are ESM-only |
Summary – Key sentences to remember
- A module = one file that exports something you want to reuse
- There are two systems: CommonJS (require) and ESM (import)
- New code in 2025–2026 → use ES Modules (“type”: “module”)
- Add .js extension in imports when using ESM
- You can mix named exports and default export in the same file
- Most modern libraries are moving to ESM — learn it early
Would you like to go deeper into any of these areas next?
- How to convert CommonJS project to ESM step-by-step
- Writing dual CommonJS + ESM packages (very useful for libraries)
- Dynamic import() – when and how to use it
- exports field in package.json (modern replacement for main)
- Common circular dependency problems & how to avoid them
- Real folder structure with 10–15 modules example
Just tell me which direction you want — I’ll continue with concrete examples. 😄
