Modules and Require
NodeJS uses a module system to organize code into reusable pieces. Understanding modules is essential for writing maintainable Node applications.
What Are Modules?
A module is simply a JavaScript file that exports functionality for other files to use. NodeJS uses the CommonJS module system by default.
// math.js - a simple module
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
// Export functions
module.exports = { add, multiply };
// app.js - using the module
const math = require('./math.js');
console.log(math.add(5, 3)); // 8
console.log(math.multiply(4, 2)); // 8
The require() Function
require() loads and executes a module, returning whatever that module exports:
// Relative path (your own modules)
const myModule = require('./myModule');
const utils = require('../utils/helpers');
// Core Node modules (built-in)
const fs = require('fs');
const path = require('path');
const http = require('http');
// NPM packages (from node_modules)
const express = require('express');
const lodash = require('lodash');
Path rules:
./or../= relative path to your file- No path prefix = core module or npm package
.jsextension is optional
Exporting from Modules
Method 1: Export Object
// calculator.js
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
module.exports = {
add,
subtract
};
Method 2: Export Single Value
// greeter.js
module.exports = function(name) {
return `Hello, ${name}!`;
};
// app.js
const greet = require('./greeter');
console.log(greet('Alice')); // "Hello, Alice!"
Method 3: Exports Shorthand
// utils.js
exports.double = (n) => n * 2;
exports.triple = (n) => n * 3;
// Same as:
// module.exports = {
// double: (n) => n * 2,
// triple: (n) => n * 3
// };
⚠️ Important: Don’t reassign exports:
// ❌ DON'T DO THIS
exports = { foo: 'bar' }; // Breaks the reference
// ✅ DO THIS INSTEAD
module.exports = { foo: 'bar' };
Core Node Modules
NodeJS comes with built-in modules for common tasks:
// File system operations
const fs = require('fs');
fs.readFileSync('data.txt', 'utf8');
// Path manipulation
const path = require('path');
const fullPath = path.join(__dirname, 'data', 'users.json');
// Operating system info
const os = require('os');
console.log(os.platform()); // 'darwin', 'win32', etc.
// HTTP server
const http = require('http');
// URL parsing
const url = require('url');
// Events
const EventEmitter = require('events');
// Utilities
const util = require('util');
Full list: nodejs.org/api
Module Patterns
Pattern 1: Export Class
// User.js
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
greet() {
return `Hi, I'm ${this.name}`;
}
}
module.exports = User;
// app.js
const User = require('./User');
const user = new User('Bob', 'bob@example.com');
console.log(user.greet());
Pattern 2: Singleton Pattern
// database.js
class Database {
constructor() {
this.connected = false;
}
connect() {
this.connected = true;
console.log('Database connected');
}
}
// Export single instance
module.exports = new Database();
// app.js
const db = require('./database');
db.connect(); // Same instance everywhere
Pattern 3: Factory Pattern
// logger.js
function createLogger(prefix) {
return {
info: (msg) => console.log(`[${prefix}] INFO: ${msg}`),
error: (msg) => console.error(`[${prefix}] ERROR: ${msg}`)
};
}
module.exports = createLogger;
// app.js
const createLogger = require('./logger');
const logger = createLogger('APP');
logger.info('Server started');
Module Caching
Modules are cached after first load:
// counter.js
let count = 0;
module.exports = {
increment: () => ++count,
getCount: () => count
};
// app.js
const counter1 = require('./counter');
const counter2 = require('./counter');
counter1.increment();
console.log(counter2.getCount()); // 1 (same instance!)
This means:
- Modules run only once
- Subsequent requires return cached version
- State is shared across all requires
Circular Dependencies
Be careful of circular requires:
// a.js
const b = require('./b');
exports.foo = () => console.log('A');
// b.js
const a = require('./a');
exports.bar = () => console.log('B');
This can cause issues. Refactor to avoid circular dependencies.
ES6 Modules (import/export)
Modern NodeJS also supports ES6 modules:
// math.mjs (note the .mjs extension)
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// app.mjs
import { add, multiply } from './math.mjs';
console.log(add(5, 3));
Or in package.json set "type": "module" to use .js extension.
For this tutorial series, we’ll stick with CommonJS (require/module.exports) as it’s still the default and most common.
Summary
| Concept | Syntax |
|---|---|
| Import module | const mod = require('./module') |
| Export object | module.exports = { a, b } |
| Export function | module.exports = function() {} |
| Export class | module.exports = MyClass |
| Shorthand exports | exports.foo = 'bar' |
| Core modules | require('fs') |
| NPM packages | require('express') |
Next Article: NPM Basics