module.exports / exports
In Node.js, you export variables, functions, and classes so they can be used from other files. In CommonJS you use module.exports or exports; in ES Modules you use export or export default.
CommonJS — module.exports
Assigning an object, function, or value to module.exports makes it available to other files via require().
kiryu.js
// kiryu.js — export Kiryu Kazuma's information
function getProfile() {
return {
name: "Kiryu Kazuma",
organization: "Dojima Family",
bgm: "Bakamitai"
};
}
function getIntro(name) {
return name + " is known as the Dragon of Dojima.";
}
// export both functions as a single object
module.exports = {
getProfile: getProfile,
getIntro: getIntro
};
main.js
// main.js — load and use kiryu.js
var kiryu = require('./kiryu');
var profile = kiryu.getProfile();
console.log(profile.name + " / " + profile.organization);
console.log(kiryu.getIntro(profile.name));
node main.js Kiryu Kazuma / Dojima Family Kiryu Kazuma is known as the Dragon of Dojima.
Difference between module.exports and exports
exports is provided as a reference (shortcut) to module.exports from the start. If you only need to add properties, you can write exports.propertyName = value.
// adding properties directly to exports (OK)
exports.name = "Majima Goro";
exports.family = "Majima Family";
// overwriting exports entirely breaks the reference to module.exports (does not work)
exports = { name: "Majima Goro" }; // this has no effect
Assigning to exports with = breaks the reference and the export stops working. When you want to assign an entire object, always use module.exports.
| Syntax | Behavior |
|---|---|
module.exports = { ... } | Replaces the exported object entirely. Also works when exporting a single function. |
exports.key = value | Adds a property to the existing module.exports object. Overwriting with = breaks the link. |
ES Modules — export / export default
ES Modules provides two types of exports: named exports (export) and default exports (export default).
majima.mjs
// majima.mjs — example of named export and default export
// named export (multiple allowed)
export var organization = "Majima Family";
export function getQuote() {
return "I'll follow you to the ends of the earth.";
}
// default export (only one per file)
export default {
name: "Majima Goro",
bgm: "GET TO THE TOP!"
};
app.mjs
// app.mjs — load majima.mjs
import majima, { organization, getQuote } from './majima.mjs';
console.log(majima.name + " / " + organization);
console.log(getQuote());
console.log("BGM: " + majima.bgm);
node app.mjs Majima Goro / Majima Family I'll follow you to the ends of the earth. BGM: GET TO THE TOP!
Named export vs. default export — when to use each
| Type | Syntax | Import syntax | Use case |
|---|---|---|---|
| Named export | export var x = ...export function f() {} | import { x, f } from './file.js' | Exporting multiple utility functions or constants. |
| Default export | export default value | import anything from './file.js' | Exporting the one main class or function of the file. |
Sample code — connecting multiple files
This sample splits character data across modules.
characters.js (CommonJS)
// characters.js — Like a Dragon character info module
var characters = [
{ name: "Kiryu Kazuma", organization: "Dojima Family", bgm: "Bakamitai" },
{ name: "Majima Goro", organization: "Majima Family", bgm: "GET TO THE TOP!" },
{ name: "Kasuga Ichiban", organization: "Ichijo Group", bgm: "Receive and Bite You" },
{ name: "Nishikiyama Akira", organization: "Nishikiyama Family", bgm: "Judgement" },
{ name: "Sawamura Haruka", organization: "Freelance", bgm: "Always in My Heart" }
];
// function that returns all characters
function getAll() {
return characters;
}
// function that searches characters by name
function findByName(name) {
return characters.find(function(c) {
return c.name === name;
}) || null;
}
module.exports = {
getAll: getAll,
findByName: findByName
};
app.js
// app.js — load and use the characters.js module
var characters = require('./characters');
// list all characters
console.log("--- Like a Dragon Characters ---");
characters.getAll().forEach(function(c, i) {
console.log((i + 1) + ". " + c.name + " [" + c.organization + "]");
});
// search by name
var found = characters.findByName("Kasuga Ichiban");
if (found) {
console.log("\nFound: " + found.name + " / BGM: " + found.bgm);
}
node app.js --- Like a Dragon Characters --- 1. Kiryu Kazuma [Dojima Family] 2. Majima Goro [Majima Family] 3. Kasuga Ichiban [Ichijo Group] 4. Nishikiyama Akira [Nishikiyama Family] 5. Sawamura Haruka [Freelance] Found: Kasuga Ichiban / BGM: Receive and Bite You
Interoperability between CommonJS and ES Modules
CommonJS and ES Modules can coexist, but there are some restrictions.
| Importer | Importee | How |
|---|---|---|
| ES Modules (import) | CommonJS (module.exports) | Works directly with import pkg from './file.cjs'. |
| CommonJS (require) | ES Modules (export) | Cannot use require(). Use dynamic import() instead. |
Common mistakes
Overwriting exports with = and breaking the reference
exports acts as a reference to module.exports, but assigning to it with = breaks that reference. After the assignment, anything set on exports is no longer reflected in module.exports, and the importing side receives an empty object.
NG (overwriting exports):
// NG: overwriting exports entirely breaks the reference to module.exports
exports = { name: "Kiryu Kazuma" };
node main.js
{}
OK (using module.exports):
// OK: use module.exports when assigning a whole object
module.exports = { name: "Kiryu Kazuma" };
node main.js
{ name: 'Kiryu Kazuma' }
Adding properties such as exports.name = "Kiryu Kazuma" is perfectly fine. The problem occurs only when you overwrite the exports variable itself with exports = ....
Circular require() — two modules requiring each other
When file A requires file B and file B also requires file A, a circular dependency occurs. To prevent an infinite loop, Node.js returns an incomplete (partially initialized) module as an empty object {} for the module that was first loaded.
a.js
// a.js
var b = require('./b');
console.log('a.js loaded b:', b);
module.exports = { from: 'a' };
b.js
// b.js
var a = require('./a'); // a.js is still initializing, so {} is returned
console.log('b.js loaded a:', a);
module.exports = { from: 'b' };
node a.js
b.js loaded a: {}
a.js loaded b: { from: 'b' }
When b.js loads a.js, the assignment to module.exports in a.js has not yet run, so b.js receives an empty object {}. To avoid this, restructure the modules to eliminate the cycle, or use a lazy require() call inside a function.
If you find any errors or copyright issues, please contact us.