Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
All Practice Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

Node.js Modules CommonJS require: Tutorial, Examples, FAQs & Interview Tips

Modules in Node.js

A module in Node.js is a file or package that contains reusable code. Instead of writing every function in one large file, modules let you break an application into smaller pieces with clear responsibilities. For example, one module might handle database logic, another might format dates, another might define routes, and another might validate user input. This makes the code easier to read, reuse, test, and maintain.

Each module has its own scope. Variables and functions declared inside one module are not automatically available in another file unless you explicitly export them. That isolation is very helpful because it prevents accidental naming conflicts and reduces the chance that unrelated parts of the program will interfere with one another.

Why Modules Matter

  • They keep large applications organized by splitting code into focused files.
  • They improve reusability because the same logic can be imported in multiple places.
  • They make testing easier since small modules are easier to verify than large mixed files.
  • They reduce global scope pollution and keep responsibilities separated.
  • They are the foundation of almost every real Node.js project structure.

Types of Modules in Node.js

Node.js projects usually work with three broad categories of modules:

  • Built-in modules - provided by Node.js itself, such as fs, http, and path.
  • Local modules - files you create inside your own project.
  • Third-party modules - packages installed from npm, such as Express or Axios.

Built-in Modules

Built-in modules come with Node.js, so you do not need to install them separately. These modules provide many of the essential features that make Node.js useful as a server-side runtime, including HTTP handling, file access, path operations, streams, events, and system information.

A built-in module is loaded with require() in CommonJS or import in ES modules. Since the module already ships with Node.js, there is no need to run npm install first.

Module Description
http Create HTTP servers and handle requests and responses.
fs Work with files and directories.
path Handle and transform file paths safely.
url Parse and construct URLs.
events Create and use event-based communication.
os Get operating system information.
util Utility helpers used in Node.js programs.

Using a Built-in Module

Using a Built-in Module
const path = require("path");

const fullPath = "C:/projects/node/app.js";

console.log(path.basename(fullPath)); // app.js
console.log(path.dirname(fullPath));  // C:/projects/node
console.log(path.extname(fullPath));  // .js

Local Modules

Local modules are files created by you inside the project. They are one of the main tools for structuring real applications. For example, in an API project, you might keep route handlers in one folder, database models in another, and utility functions in another. Instead of writing everything inside index.js or server.js, you split the logic into multiple files and import only what you need.

When you load a local module in CommonJS, you use a relative path such as ./math.js or ../utils/logger.js. The ./ means "from the current folder." This is different from built-in modules and installed packages, which are referenced by name only.

This example shows one of the most common export patterns: exporting an object that contains several functions. It is simple, readable, and useful when a module needs to provide multiple related utilities.

Local Module Example

Local Module Example
// math.js
function add(a, b) {
    return a + b;
}

function multiply(a, b) {
    return a * b;
}

module.exports = {
    add,
    multiply
};

Local Modules

Local Modules
// app.js
const math = require("./math");

console.log(math.add(5, 3));      // 8
console.log(math.multiply(4, 6)); // 24

Third-Party Modules

Third-party modules are external packages installed from npm. They allow you to reuse code written by the wider community instead of implementing every feature yourself. For example, Express helps you create web servers more easily, Axios helps you call APIs, and Dotenv helps you load environment variables from a file.

Third-party packages are stored in node_modules and tracked through package.json and package-lock.json. This makes it easy for other developers to install the same dependencies by running npm install.

Install and Use a Package

Install and Use a Package
npm install lodash

Third-Party Modules

Third-Party Modules
const _ = require("lodash");

const numbers = [1, 2, 3, 4, 5];
const reversed = _.reverse([...numbers]);

console.log(reversed); // [5, 4, 3, 2, 1]

CommonJS Modules

Historically, Node.js used the CommonJS module system by default. In CommonJS, code is imported with require() and exported with module.exports or exports. Many existing Node.js tutorials, packages, and codebases still use this format, so it remains very important to understand.

A useful guideline is this: use module.exports when you want to export one main value, and use exports.someName when you want to expose several named members. Many developers prefer module.exports = { ... } even for multiple exports because it keeps the structure explicit in one place.

CommonJS Export Patterns

CommonJS Export Patterns
// Export one function directly
module.exports = function greet(name) {
    return `Hello, ${name}`;
};

CommonJS Modules

CommonJS Modules
// Export multiple named items
exports.add = (a, b) => a + b;
exports.subtract = (a, b) => a - b;

ES Modules

Modern Node.js also supports ES Modules, which use import and export syntax. This is the standard JavaScript module format used in browsers as well. ES Modules can be enabled by using the .mjs file extension or by setting "type": "module" inside package.json.

If your project uses ES Modules, keep the syntax consistent. Mixing CommonJS and ESM without understanding the differences can create confusing import behavior. Many modern projects use ESM, but CommonJS is still extremely common in the Node.js ecosystem.

ES Module Example

ES Module Example
// math.mjs
export function add(a, b) {
    return a + b;
}

export function multiply(a, b) {
    return a * b;
}

ES Modules

ES Modules
// app.mjs
import { add, multiply } from "./math.mjs";

console.log(add(2, 7));      // 9
console.log(multiply(3, 4)); // 12

How require() Resolves Modules

The require() function does more than just "open a file." It follows a resolution process. If you pass a built-in module name like fs, Node.js loads the built-in module. If you pass a relative path like ./utils/helper, Node.js searches your project folders for that file. If you pass a package name like express, Node.js looks in node_modules.

This behavior explains why the syntax differs by module type. A relative path means "use my own file," while a bare package name means "load a built-in or installed package." Understanding this saves a lot of time when debugging "Cannot find module" errors.

Module Caching

Node.js caches modules after the first time they are loaded. That means if the same module is required again elsewhere, Node.js usually returns the already loaded instance instead of reading and executing the file from scratch. This improves performance and also means module-level state can be shared.

This cached behavior is useful, but it also means you should be careful with mutable shared state inside modules. If a module stores changing values at the top level, that state may be reused across different parts of the application.

Module Cache Behavior

Module Cache Behavior
// counter.js
let count = 0;

module.exports = function increment() {
    count++;
    return count;
};

Module Caching

Module Caching
// app.js
const increment = require("./counter");

console.log(increment()); // 1
console.log(increment()); // 2
console.log(increment()); // 3

Folder Structure Example

Modules become much more meaningful when you see how they shape a real project. A beginner Node.js application might be organized like this:

In this structure, server.js may start the application, routes/users.js may define user routes, services/userService.js may contain business logic, and utils/logger.js may provide reusable logging functions. This separation is one of the main reasons modules are so valuable.

Simple Project Structure

Simple Project Structure
my-app/
  package.json
  server.js
  routes/
    users.js
  services/
    userService.js
  utils/
    logger.js

Common Beginner Mistakes

A common mistake is forgetting the relative path prefix when importing a local file. Writing require("math") tries to load a package or built-in module, while require("./math") loads your own file. Another mistake is mixing exports and module.exports carelessly. Since exports is just a reference, reassigning it directly can break expected exports. Beginners also sometimes assume modules are re-executed from scratch every time, forgetting that CommonJS modules are cached.

It is also easy to create modules that are too large. If one file handles routing, validation, database logic, and utility formatting together, the code becomes harder to test and maintain. Smaller modules with one clear purpose are usually easier to work with.

A Practical Mental Model

Think of a module as a tool drawer. Each drawer contains a specific group of tools for a specific job. If you need math helpers, open the math drawer. If you need logging helpers, open the logger drawer. If everything is thrown into one giant box, finding and reusing the right piece becomes difficult. Modules give a Node.js project a structure that scales as the application grows.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.