Learn how Node.js organizes code into modules, use require/exports, and understand the module system.
Imagine writing an entire web application in a single file — thousands of lines of code for authentication, database queries, API routes, email sending, payment processing, and utility functions, all mixed together. Finding a bug would be like searching for a specific grain of sand on a beach. Changing one thing could break something completely unrelated. This is why every serious programming language has a module system.
Modules let you split your code into separate files, each responsible for one specific thing. A database.js module handles database connections. An auth.js module handles login and registration. A utils.js module has helper functions. Each module is a self-contained unit with its own scope — variables defined inside a module do not leak into other modules.
The benefits of using modules are significant:
formatDate() function, every file that needs date formatting can import it.count without interfering with each other. Each module has its own scope.Node.js was built with modules in mind from the very beginning. Every .js file in Node.js is automatically treated as a separate module.
Node.js originally used (and still supports) the CommonJS module system. This is the require() and module.exports pattern you will see in much of the existing Node.js code online.
Exporting from a module — Use module.exports to make things available to other files:
// math.js
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
module.exports = { add, multiply };You can also export a single value:
// greet.js
module.exports = function(name) {
return "Hello, " + name + "!";
};Importing a module — Use require() to load a module:
// app.js
const math = require('./math'); // Import our math module
const greet = require('./greet'); // Import our greet module
console.log(math.add(5, 3)); // 8
console.log(math.multiply(4, 7)); // 28
console.log(greet('Alice')); // Hello, Alice!Notice the ./ before the file name — this tells Node.js to look for a local file relative to the current file. Without ./, Node.js would look for a built-in module or an installed npm package instead.
Each file gets its own scope automatically. If math.js defines a variable called secretKey, it is invisible to app.js unless explicitly exported. This is a key difference from browser JavaScript, where all scripts loaded via <script> tags share the same global scope and can accidentally overwrite each other's variables.
ES Modules (ESM) are the modern, standardized JavaScript module system. They use the import and export keywords that you may have already seen in frontend frameworks like React. Node.js has supported ES Modules since version 12, and they are now the recommended approach for new projects.
To use ES Modules in Node.js, you need to either:
"type": "module" in your package.json file, OR.mjs file extension instead of .jsNamed exports — Export multiple things by name:
// math.mjs
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
export const PI = 3.14159;Importing named exports:
// app.mjs
import { add, multiply, PI } from './math.mjs';
console.log(add(5, 3)); // 8
console.log(PI); // 3.14159Default export — Export one main thing from a module:
// greet.mjs
export default function(name) {
return "Hello, " + name + "!";
}import greet from './greet.mjs';
console.log(greet('Alice')); // Hello, Alice!The key differences from CommonJS: import/export are static — they must be at the top level of the file (not inside an if block or a function). This allows tools to analyze your code and optimize it (called tree-shaking — removing unused exports). Most modern projects, including Next.js and React apps, use ES Modules. You will encounter both systems in the real world, so knowing both is important.
<div style="font-family:sans-serif; padding:16px;">
<h3>CommonJS vs ES Modules</h3>
<div style="display:flex; gap:16px; flex-wrap:wrap;">
<!-- CommonJS -->
<div style="flex:1; min-width:280px; border:2px solid #3b82f6; border-radius:8px; overflow:hidden;">
<div style="background:#3b82f6; color:white; padding:8px 12px; font-weight:bold;">CommonJS (require)</div>
<pre style="padding:12px; margin:0; font-size:13px; background:#f8fafc; overflow-x:auto;">// utils.js
function formatDate(date) {
return date.toLocaleDateString();
}
function capitalize(str) {
return str[0].toUpperCase() + str.slice(1);
}
module.exports = { formatDate, capitalize };
// app.js
const { formatDate, capitalize } = require('./utils');
console.log(capitalize('hello')); // Hello
console.log(formatDate(new Date())); </pre>
</div>
<!-- ES Modules -->
<div style="flex:1; min-width:280px; border:2px solid #10b981; border-radius:8px; overflow:hidden;">
<div style="background:#10b981; color:white; padding:8px 12px; font-weight:bold;">ES Modules (import/export)</div>
<pre style="padding:12px; margin:0; font-size:13px; background:#f8fafc; overflow-x:auto;">// utils.mjs
export function formatDate(date) {
return date.toLocaleDateString();
}
export function capitalize(str) {
return str[0].toUpperCase() + str.slice(1);
}
// app.mjs
import { formatDate, capitalize } from './utils.mjs';
console.log(capitalize('hello')); // Hello
console.log(formatDate(new Date()));</pre>
</div>
</div>
</div>Node.js comes with a rich set of built-in modules that you can use without installing anything. These are part of Node.js itself and provide core functionality that backend applications need:
fs (File System) — Read, write, create, and delete files and directories on the computer:
const fs = require('fs');
const data = fs.readFileSync('config.json', 'utf8');
fs.writeFileSync('output.txt', 'Hello World');path — Work with file and directory paths in a cross-platform way:
const path = require('path');
const fullPath = path.join(__dirname, 'data', 'users.json');
const ext = path.extname('photo.jpg'); // '.jpg'http — Create web servers and make HTTP requests:
const http = require('http');
const server = http.createServer((req, res) => {
res.end('Hello World');
});
server.listen(3000);crypto — Cryptographic functions for hashing, encryption, and generating secure random values:
const crypto = require('crypto');
const hash = crypto.createHash('sha256').update('password').digest('hex');os — Get operating system information:
const os = require('os');
console.log(os.hostname()); // Your computer's name
console.log(os.cpus().length); // Number of CPU coresurl — Parse and construct URLs. events — Create event emitters. stream — Handle streaming data. child_process — Run shell commands from Node.js.
You require built-in modules by name (no ./ prefix). When Node.js sees require('fs'), it knows to load the built-in file system module rather than looking for a local file called fs.js.
What function is used to import a module in CommonJS?