Skip to main content
Knowledge Hub

Node.js Modules and Global Object

Understanding the module system and global scope in Node.js

Last updated: May 15, 2025

In Node.js, the global object provides access to globally available variables and functions without needing imports. It solves the problem of the absence of the window object common in browsers.

Understanding how Node.js handles modules and global scope is fundamental to organizing code and avoiding common pitfalls.

Global Object in Node.js

Global Variables and Functions

global: Access or define global variables.

global.myVar = 100;
console.log(myVar); // Output: 100

globalThis: Standard way to refer to the global object across environments.

globalThis.myVar = 200;
console.log(myVar); // Output: 200

Built-in Objects

process: Provides information about the current process.

console.log(process.version); // Output: Node.js version
console.log(process.env.NODE_ENV); // Output: current environment

require(): Import modules.

const fs = require('fs');

Buffer: Handle binary data.

const buffer = Buffer.from('Hello');
console.log(buffer); // Output: <Buffer 48 65 6c 6c 6f>

Global Constants

console.log(NaN);        // Output: NaN
console.log(Infinity);   // Output: Infinity
console.log(undefined);  // Output: undefined

Timer Functions

setTimeout() and setInterval(): Delay or repeat code execution.

setTimeout(() => {
  console.log("Runs once after 2 seconds");
}, 2000);

setInterval(() => {
  console.log("Runs every 2 seconds");
}, 2000);

console

Used for logging to the console.

console.log("Hello, World!");  // Output: Hello, World!
console.error("This is an error!"); // Output: This is an error!

Node.js Module System

Where Do dirname and filename Come From?

In Node.js, dirname and filename are special variables automatically provided by the module system. They contain the absolute paths to the current module’s directory and file, respectively.

These are not part of the global object, but they are implicitly available in every module.

console.log(__dirname);  // Output: Absolute path of current directory
console.log(__filename); // Output: Absolute path of current file

Why Don’t Variables Automatically Become Global?

In contrast to the browser’s window object, Node.js does not automatically make variables global. Each module in Node.js has its own isolated scope.

This prevents conflicts between different modules’ variables, which would otherwise lead to unintended behavior.

// In browser
let v = 3;
console.log(window.v); // Output: 3

// In Node.js
let v = 3;
console.log(global.v); // Output: undefined

Where Does module Come From?

The module object is automatically created for every file in Node.js. It contains metadata about the module, including exports, filename, and others.

When you call console.log(module), it outputs the details of the current module, including its exports object, which holds what the module is exporting.

How Node.js Solves the Global Scope Problem

In vanilla JavaScript, variables in different scripts can overlap in the global scope, causing conflicts:

// test.js
var a = 7;

// test1.js
var b = 9;
console.log(a + b); // Output: 16

In an HTML file, if both scripts are included, the global scope is shared, and the result is 16 because the variables are not encapsulated.

Node.js solves this by wrapping each file/module in an Immediately Invoked Function Expression (IIFE). This keeps variables isolated within their own scope, preventing conflicts.

(function(exports, require, module, __filename, __dirname) {
  // Your module code here
  return module.exports;
});

This wrapper function is automatically applied to every module, providing the special variables (exports, require, module, filename, dirname) and keeping the module’s variables private.

Node.js Module Example

In Node.js, when you require a module, its code is executed, and the module’s exports object is returned. Here’s how you encapsulate a module:

// people.js
var people = ["John", "Jane"];
module.exports = { people };

// index.js
const people = require("./people");
console.log(people);  // Output: { people: ['John', 'Jane'] }

You manually export data with module.exports to make it available for other files to use.

exports and module.exports

The exports object is initialized as an empty object. To expose variables or functions from a module, you can assign them to module.exports.

// people.js
var people = ["John", "Jane"];
module.exports = { people };

// index.js
const people = require("./people");
console.log(people);  // Output: { people: ['John', 'Jane'] }

By default, exports is empty, but when you assign values to module.exports, they are shared across files.

Different Export Styles

// Export a single function
module.exports = function greet(name) {
  console.log(`Hello, ${name}!`);
};

// Export multiple items
module.exports = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b
};

// Or using exports shorthand
exports.add = (a, b) => a + b;
exports.subtract = (a, b) => a - b;

Important note: You can add properties to exports, but you cannot reassign it. Always reassign module.exports if you want to export a single value.

// This works
exports.myFunc = () => {};

// This does NOT work (breaks the reference)
exports = { myFunc: () => {} };

// Use this instead
module.exports = { myFunc: () => {} };

How require() Works

When you require a module:

  1. Node.js resolves the module path
  2. Checks if the module is already cached
  3. If not cached, reads the file
  4. Wraps it in the IIFE
  5. Executes the wrapped function
  6. Caches the result
  7. Returns module.exports

This means modules are only executed once, even if required multiple times. Subsequent requires return the cached exports.

// counter.js
let count = 0;
module.exports = {
  increment() { count++; },
  getCount() { return count; }
};

// main.js
const counter1 = require('./counter');
const counter2 = require('./counter');

counter1.increment();
console.log(counter2.getCount()); // Output: 1 (same instance)

Module Caching

Modules are cached after the first time they are loaded. This means the module code is only executed once, and subsequent requires return the cached module.exports.

// config.js
console.log("Config loaded");
module.exports = { apiKey: "secret" };

// main.js
const config1 = require('./config'); // Logs: "Config loaded"
const config2 = require('./config'); // No log (cached)
console.log(config1 === config2); // true (same object)

Summary

Node.js’s module system uses encapsulation to ensure each file/module has its own isolated scope, avoiding global conflicts. The require() function is used to load modules, and module.exports controls what a module exposes.

FeatureBrowserNode.js
Global Objectwindowglobal/globalThis
Module SystemES ModulesCommonJS
Variable ScopeGlobal by defaultModule-scoped
Special VariablesNonedirname, filename, module, exports, require

Understanding Node.js modules is essential for organizing code, managing dependencies, and building maintainable applications. The module system’s encapsulation prevents the common pitfalls of global scope pollution that plague browser JavaScript.