Node.js Modules: Complete Tutorial

Build reusable, maintainable, and scalable Node.js applications

Core Concepts Practical Patterns Interview Ready

Table of Contents

  1. What are Modules?
  2. Types of Modules
  3. Core Modules
  4. Local Modules
  5. Module Exports
  6. Module Import (require)
  7. ES6 Modules (import/export)
  8. Module Caching
  9. Module Wrapper Function
  10. Module Patterns
  11. Practical Examples
  12. Best Practices

What are Modules?

Modules are reusable blocks of code that encapsulate related functionality. They keep applications organized, maintainable, and scalable.

BenefitDescription
Code ReusabilityWrite once, use in multiple files/projects
OrganizationGroup related functionality logically
EncapsulationHide implementation details
MaintainabilityEasier debugging and updates
Namespace ManagementAvoid global scope pollution
Dependency ManagementTrack 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

ModulePurposeExample
fsFile operationsRead/write files
pathPath utilitiesJoin/resolve paths
httpHTTP server/clientCreate server
osSystem infoCPU, memory, platform
eventsEventEmitterCustom events
cryptoHashes/encryptionHashing, 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

  1. Core modules
  2. Relative/absolute file modules
  3. Directory modules (`index.js` / package main)
  4. `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

FeatureCommonJSES Modules
Syntaxrequire/module.exportsimport/export
LoadingSynchronousStatic + async capable
Tree shakingNoYes
Default in NodeYesSupported 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

  1. Keep modules focused (single responsibility).
  2. Use descriptive filenames and exported symbols.
  3. Export at bottom for readability.
  4. Avoid circular dependencies.
  5. Use index files for folder-level exports.
  6. Use specific error types instead of generic errors.
  7. Document module API with comments/JSDoc.

10 Interview Questions + 10 MCQs

Interview Pattern 10 Q&A
1Why 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?

Aimport x from 'x'
Brequire('x')
Cinclude('x')
Dload('x')
Explanation: CommonJS uses require().
2

Which is a core module?

Aexpress
Blodash
Cfs
Dmongoose
Explanation: fs is built into Node.js.
3

What does module caching return on second require of same path?

ANew instance
BCached instance
CError
DUndefined
Explanation: Node returns cached module object.
4

Which file extension is commonly used for ESM without package type?

A.cjs
B.mjs
C.njs
D.esm
Explanation: .mjs enables ES modules explicitly.
5

Correct way to export a class in CommonJS?

Aexport class A {}
Bmodule.exports = class A {}
Cexports = class A {}
Drequire.class = A
Explanation: Replacing full export should use module.exports.
6

Which variable gives current module directory?

A__dirname
Bcwd
Cmodule.path()
D__folder
Explanation: __dirname is provided by wrapper function.
7

Which pattern is best for configurable object creation?

AFactory pattern
BSingleton only
CGlobal variables
DCircular require
Explanation: Factory creates customized instances cleanly.
8

Which call clears one module from cache?

Arequire.clear()
Bdelete require.cache[require.resolve('./m')]
Cmodule.reset()
Drequire.reload('./m')
Explanation: Delete by resolved key from require.cache.
9

Main risk of circular dependencies?

AFaster startup
BIncomplete module objects
CSmaller bundle size
DBetter tree-shaking
Explanation: Circular imports may expose partially initialized exports.
10

Recommended way to aggregate folder modules?

AUse index.js exports
BGlobal requires
CCopy code manually
DDisable linting
Explanation: Index re-exports keep imports clean and scalable.