Understanding module.exports
in Node.js: A Complete Guide π
When I was reading through a some.config.js
file in a project, I came across this line:
module.exports = { ... };
At first glance, it looked ordinary. But then I asked myself:
π How does module.exports
really work in Node.js?
This question sent me on a deep dive into Nodeβs module system β from how files are wrapped, to how require()
works, and how exports
differs from module.exports
.
Hereβs what I learned (and what every JavaScript/Node developer should know) π
πΉ What is module.exports
in Node.js? π‘
In Node.js, every file is treated as a module.
When Node loads a file, it doesnβt run it directly. Instead, it wraps your code like this:
(function (exports, require, module, __filename, __dirname) { // your file content });
This wrapper gives each file access to:
exports
require
module
__filename
__dirname
Thatβs why you can use module.exports
anywhere in your file without explicitly importing it.
πΉ The Relationship Between exports
and module.exports
π
At the beginning of every module, Node does this:
exports = module.exports = {};
This means:
-
exports
is just a reference tomodule.exports
. - By default, both point to the same object.
- Whatever you add to either (without reassigning) will be exported.
β
Example:
exports.a = 10; // works module.exports.b = 20; // works
Result:
{ a: 10, b: 20 }
πΉ The Common Mistake β οΈ
If you reassign exports
, you break the link:
// β Won't work exports = function () { console.log("Hello"); };
Now exports
points to a new function, but module.exports
is still {}
.
So nothing gets exported.
β
Correct way:
module.exports = function () { console.log("Hello"); };
πΉ How Does require()
Work? π
When you write:
const myModule = require("./myModule");
Hereβs the behind-the-scenes flow:
- Node resolves the file path (
./myModule.js
) - Checks the module cache (modules load once per runtime)
- Wraps and executes the file inside the function wrapper
- Returns
module.exports
π‘ Thatβs why require()
always gives you module.exports
β not exports
.
πΉ Example: Using module.exports
in Practice π
// user.js module.exports = { name: "Yogesh", greet() { console.log(`Hello, ${this.name}`); } };
// app.js const user = require("./user"); console.log(user.name); // Yogesh user.greet(); // Hello, Yogesh
πΉ CommonJS vs ES Modules (CJS vs ESM) β‘
Modern Node.js supports both CommonJS (CJS) and ES Modules (ESM).
β
CommonJS (default in Node)
// math.js module.exports = { add: (a, b) => a + b }; // app.js const math = require("./math"); console.log(math.add(2, 3));
β
ES Modules (modern JS standard)
// math.mjs export function add(a, b) { return a + b; } // app.mjs import { add } from "./math.mjs"; console.log(add(2, 3));
π Key differences:
- Syntax β
module.exports
vsexport
/import
- Loading β CommonJS is synchronous; ES Modules are asynchronous
- Exports β CommonJS typically exports a single object; ESM supports multiple named exports
- Future-proofing β ESM is the official JavaScript standard, better for modern apps
πΉ Best Practices β
- Use
exports.x = β¦
for adding multiple exports - Use
module.exports = β¦
when exporting one main thing (function, class, or object) - Prefer ES Modules (
import/export
) in new projects if supported
β¨ Conclusion
That little module.exports
line in some.config.js
turned out to be a doorway into Node.js internals.
What looks simple β
module.exports = { ... };
β is backed by a powerful module system that:
- Wraps files in functions
- Links
exports
andmodule.exports
- Returns only
module.exports
throughrequire()
- Supports both CommonJS and ES Modules
Next time you use module.exports
, remember:
Itβs not just boilerplate β itβs the heart of how Node.js manages modules.
βοΈ Written by Yogesh Bamanier
π LinkedIn
Top comments (0)