Tutorials Logic, IN info@tutorialslogic.com

Node.js Modules CommonJS require

Node.js Modules CommonJS require

Node.js is a practical Node.js topic that becomes clear when you connect the definition to a small working example.

Use this page to understand what happens, why it happens, how to verify it, and what mistake usually breaks the concept.

After reading, practice Node.js with a normal case, a boundary case, and a broken case so the idea becomes usable instead of memorized.

Node.js Modules CommonJS require should be studied as a practical Node.js backend development lesson, not as a label. Start by naming the input, the rule that changes the input, and the result a learner should be able to predict after reading the page.

In the node-js > modules page, the notes should connect the definition with a working scenario, a mistake that beginners actually make, and the exact check that proves the fix. That makes the topic useful for coding, debugging, and interview revision.

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.

Deep Study Notes for Node.js

Node.js should be learned as a practical Node.js skill, not only as a definition. Start by asking what problem the topic solves, what input or state it receives, what rule it applies, and what visible result proves it worked.

A strong explanation of Node.js includes the normal case, a boundary case, and a failure case. When you practice, write down the before-state, the operation, the after-state, and the reason the result changed.

This lesson was expanded because the audit reported: limited checklist/practice/mistake/FAQ notes . The added notes below focus on clearer explanation, more examples, and concrete practice so the topic is easier to understand from the page itself.

  • Define the exact problem solved by Node.js before looking at syntax.
  • Trace one small example by hand and describe every step in plain language.
  • Identify what changes when the input is empty, repeated, invalid, delayed, or larger than expected.
  • Connect the topic to a realistic project scenario instead of treating it as isolated theory.
  • Verify your answer with output, logs, query results, browser behavior, compiler feedback, or a state table.

Worked Explanation: Using Node.js Correctly

Imagine you are adding Node.js to a small learning project. The first step is to choose the smallest scenario that still shows the main idea. Avoid starting with a large production design; it hides the concept behind too many details.

Next, isolate the moving parts. Name the input, the rule, the output, and the possible error. This habit makes the topic easier to debug because you can see whether the problem is caused by bad data, wrong configuration, incorrect syntax, timing, permissions, or misunderstanding of the rule.

Finally, compare two versions: one correct version and one intentionally broken version. The broken version is valuable because it teaches you how the topic fails in real work, which is usually what interviews and debugging tasks test.

  • Normal case: show the expected behavior with simple, valid input.
  • Boundary case: test the smallest, largest, empty, repeated, or unusual value that still belongs to the topic.
  • Failure case: introduce one realistic mistake and explain the symptom it creates.
  • Repair step: change one thing at a time so you know exactly what fixed the problem.

Node.js runnable Node.js example

Node.js runnable Node.js example
const topic = 'Node.js';
const input = ['normal', 'empty', 'error'];

for (const item of input) {
  console.log(`${topic}: handling ${item} case`);
}

// Run with: node node_js.js

Node.js async error handling example

Node.js async error handling example
async function explainNodeJs() {
  try {
    const result = await Promise.resolve('Node.js completed');
    console.log(result);
  } catch (error) {
    console.error('Handle the failure path clearly:', error.message);
  }
}

explainNodeJs();
Key Takeaways
  • State the purpose of Node.js in one sentence before using it.
  • Create a tiny Node.js example that demonstrates the topic without unrelated code.
  • Test one normal input, one edge input, and one incorrect input for Node.js.
  • Explain the result using before-state, operation, and after-state.
  • Add a verification step such as output, logs, query results, browser behavior, or compiler feedback.
Common Mistakes to Avoid
WRONG Memorizing Node.js as a definition only.
RIGHT Pair the definition with a small working example and a failure example.
The fastest way to remember the topic is to explain why the output changes.
WRONG Copying syntax without checking the state before and after.
RIGHT Write the input state, apply the rule, then inspect the output state.
State tracing turns confusing behavior into a visible sequence.
WRONG Ignoring the error path for Node.js.
RIGHT Create one intentionally broken version and document the symptom and fix.
A page is much easier to learn from when it explains both success and failure.
WRONG Memorizing Node.js Modules CommonJS require without the situation where it is useful.
RIGHT Connect Node.js Modules CommonJS require to a concrete Node.js backend development task.
Purpose makes syntax easier to recall.

Practice Tasks

  • Build the smallest working demo for Node.js and write what each line does.
  • Change one input or setting and predict the result before running it.
  • Break the example in a realistic way, then fix it and describe the repair.
  • Create a two-column note comparing when to use Node.js and when another approach is better.
  • Explain Node.js aloud as if teaching a beginner who knows basic Node.js only.

Frequently Asked Questions

Understand the problem it solves, the input or state it works on, and the visible result that proves the concept is working.

Use one tiny correct example, one boundary example, and one broken example. Compare the output or state after each change.

They often memorize the term without tracing the behavior. Tracing makes the rule easier to remember and debug.

Remember the problem it solves in Node.js backend development, then attach the syntax or steps to that problem.

Ready to Level Up Your Skills?

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