Node.js Modules: Complete Tutorial
Build reusable, maintainable, and scalable Node.js applications
Core Concepts
Practical Patterns
Interview Ready
Table of Contents
What are Modules?
Modules are reusable blocks of code that encapsulate related functionality. They keep applications organized, maintainable, and scalable.
| Benefit | Description |
|---|---|
| Code Reusability | Write once, use in multiple files/projects |
| Organization | Group related functionality logically |
| Encapsulation | Hide implementation details |
| Maintainability | Easier debugging and updates |
| Namespace Management | Avoid global scope pollution |
| Dependency Management | Track and manage dependencies clearly |
Think of modules like LEGO blocks: each block has a specific purpose, can be reused, combined, and replaced safely.
Types of Modules
Node.js Modules
1) Core Modules (built-in)
2) Local Modules (user-created)
3) Third-party Modules (npm)
Core Modules
const fs = require('fs');
const path = require('path');
const http = require('http');
Local Modules
const myModule = require('./myModule.js');
const utils = require('./utils');
Third-party Modules
const express = require('express');
const lodash = require('lodash');
Core Modules
| Module | Purpose | Example |
|---|---|---|
| fs | File operations | Read/write files |
| path | Path utilities | Join/resolve paths |
| http | HTTP server/client | Create server |
| os | System info | CPU, memory, platform |
| events | EventEmitter | Custom events |
| crypto | Hashes/encryption | Hashing, UUID |
fs Example
const fs = require('fs');
fs.readFile('./example.txt', 'utf8', (err, data) => {
if (err) console.error(err);
else console.log(data);
});
path Example
const path = require('path');
console.log(path.extname('file.txt'));
console.log(path.join('/users', 'john', 'docs'));
events Example
const EventEmitter = require('events');
const emitter = new EventEmitter();
emitter.on('login', user => console.log(`${user} logged in`));
emitter.emit('login', 'Alice');
http Example
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello Node.js!');
}).listen(3000);
Local Modules
math.js
const PI = 3.14159;
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
function multiply(a, b) { return a * b; }
function divide(a, b) { if (b === 0) throw new Error('Division by zero'); return a / b; }
function circleArea(r) { return PI * r * r; }
module.exports = { add, subtract, multiply, divide, circleArea };
app.js
const math = require('./math.js');
console.log(math.add(10, 5));
console.log(math.circleArea(5));
Module Exports
// module.exports vs exports
console.log(module.exports === exports); // true initially
// Correct
module.exports = { add: (a, b) => a + b };
// Also correct
exports.add = (a, b) => a + b;
Export Patterns
- Export object with multiple functions
- Export a class
- Export a single function
- Export singleton instance
Module Import (require)
const fs = require('fs'); // core
const myModule = require('./myModule'); // local
const express = require('express'); // npm
const config = require('./config.json'); // json
Resolution Order
- Core modules
- Relative/absolute file modules
- Directory modules (`index.js` / package main)
- `node_modules` search
ES6 Modules (import/export)
Using .mjs
// math.mjs
export function add(a, b) { return a + b; }
export const PI = 3.14159;
// app.mjs
import { add, PI } from './math.mjs';
Using package.json
{
"type": "module"
}
CommonJS vs ESM
| Feature | CommonJS | ES Modules |
|---|---|---|
| Syntax | require/module.exports | import/export |
| Loading | Synchronous | Static + async capable |
| Tree shaking | No | Yes |
| Default in Node | Yes | Supported with config |
Module Caching
// counter.js
let count = 0;
module.exports = { increment: () => ++count, getCount: () => count };
// app.js
const c1 = require('./counter');
const c2 = require('./counter');
c1.increment();
console.log(c2.getCount()); // 1 (shared cache)
delete require.cache[require.resolve('./myModule')];
const fresh = require('./myModule');
Module Wrapper Function
(function(exports, require, module, __filename, __dirname) {
// your module code
});
This gives each module scope isolation and special variables like __filename and __dirname.
Module Patterns
- Revealing Module: expose selected methods, keep internals private.
- Class Module: export class for stateful objects.
- Factory Module: create configured instances dynamically.
- Singleton: single shared instance (config/db manager).
- Plugin Architecture: register and initialize extensible plugins.
// singleton config
class Config { get(key) { /* ... */ } }
module.exports = new Config();
Practical Examples
1) Authentication Module
const crypto = require('crypto');
const users = new Map();
module.exports = {
register(username, password) { /* hash + store */ },
login(username, password) { /* verify + token */ }
};
2) Validator Module
module.exports = {
isEmail(v) { return /^[^\s@]+@([^\s@.,]+\.)+[^\s@.,]{2,}$/.test(v); },
minLength: n => v => v.length >= n
};
3) API Client Module
class APIClient {
get(path) { return this.request('GET', path); }
post(path, data) { return this.request('POST', path, data); }
}
module.exports = APIClient;
4) Config Module
class Config {
get(key) { /* dot path getter */ }
set(key, value) { /* dot path setter */ }
}
module.exports = new Config();
Best Practices
- Keep modules focused (single responsibility).
- Use descriptive filenames and exported symbols.
- Export at bottom for readability.
- Avoid circular dependencies.
- Use index files for folder-level exports.
- Use specific error types instead of generic errors.
- Document module API with comments/JSDoc.
10 Interview Questions + 10 MCQs
Interview Pattern 10 Q&A1Why are modules important in Node.js?easy
Answer: They improve organization, reusability, maintainability, and scope isolation.
2Difference between core, local, and third-party modules?easy
Answer: Core are built-in, local are app-created, third-party are installed from npm.
3When should you use module.exports over exports?medium
Answer: Use
module.exports when replacing whole export object/function/class.4How does module caching affect app behavior?medium
Answer: Same module path returns shared cached instance, preserving state between imports.
5What problems can circular dependencies cause?hard
Answer: Incomplete initialization, undefined imports, and hard-to-debug runtime issues.
6How do ES modules differ from CommonJS at load time?medium
Answer: CommonJS loads synchronously at runtime; ESM has static structure and better tooling/tree-shaking support.
7What does require.resolve() do?medium
Answer: It returns the fully resolved filename path for a module.
8When is singleton module pattern useful?medium
Answer: For shared config, centralized connections, or single state manager across app.
9What are wrapper function parameters in Node modules?easy
Answer:
exports, require, module, __filename, __dirname.10How would you structure modules in a large Node API?hard
Answer: Organize by domain/layer (routes/controllers/services/repositories) with clear module contracts.
10 Node.js Modules MCQs
1
Which syntax imports a CommonJS module?
Explanation: CommonJS uses
require().2
Which is a core module?
Explanation:
fs is built into Node.js.3
What does module caching return on second require of same path?
Explanation: Node returns cached module object.
4
Which file extension is commonly used for ESM without package type?
Explanation:
.mjs enables ES modules explicitly.5
Correct way to export a class in CommonJS?
Explanation: Replacing full export should use
module.exports.6
Which variable gives current module directory?
Explanation:
__dirname is provided by wrapper function.7
Which pattern is best for configurable object creation?
Explanation: Factory creates customized instances cleanly.
8
Which call clears one module from cache?
Explanation: Delete by resolved key from
require.cache.9
Main risk of circular dependencies?
Explanation: Circular imports may expose partially initialized exports.
10
Recommended way to aggregate folder modules?
Explanation: Index re-exports keep imports clean and scalable.