Skip to main content
Course/Module 1/Topic 3 of 4Beginner

Modules & NPM

Learn Node.js module system, CommonJS vs ES modules, and NPM package management

45 minBy Priygop TeamLast updated: Feb 2026

Node.js Module System

Node.js has a built-in module system that allows you to organize your code into reusable pieces. Modules help you create maintainable and scalable applications by separating concerns and avoiding global scope pollution.

CommonJS Modules

Example
// math.js - Exporting modules
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
const multiply = (a, b) => a * b;
const divide = (a, b) => a / b;

// Export individual functions
module.exports.add = add;
module.exports.subtract = subtract;

// Export as an object
module.exports = {
    add,
    subtract,
    multiply,
    divide
};

// app.js - Importing modules
const math = require('./math');

console.log(math.add(5, 3));      // 8
console.log(math.subtract(10, 4)); // 6
console.log(math.multiply(2, 6));  // 12
console.log(math.divide(15, 3));   // 5

// Destructuring imports
const { add, subtract } = require('./math');
console.log(add(5, 3));      // 8
console.log(subtract(10, 4)); // 6

ES Modules

Example
// math.js - ES Module exports
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;
export const divide = (a, b) => a / b;

// Default export
const calculator = {
    add,
    subtract,
    multiply,
    divide
};

export default calculator;

// app.js - ES Module imports
import { add, subtract, multiply, divide } from './math.js';
import calculator from './math.js';

console.log(add(5, 3));      // 8
console.log(calculator.multiply(2, 6)); // 12

// Dynamic imports
async function loadModule() {
    const math = await import('./math.js');
    console.log(math.add(5, 3));
}

loadModule();

NPM Package Management

Example
// Initialize a new project
npm init -y

// Install dependencies
npm install express
npm install --save-dev nodemon

// Install specific version
npm install express@4.18.2

// Install globally
npm install -g nodemon

// Remove package
npm uninstall express

// Update packages
npm update

// List installed packages
npm list

// Run scripts
npm start
npm test
npm run dev

// package.json example
{
  "name": "my-node-app",
  "version": "1.0.0",
  "description": "A Node.js application",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "jest"
  },
  "dependencies": {
    "express": "^4.18.2"
  },
  "devDependencies": {
    "nodemon": "^2.0.22"
  }
}

ES Modules vs CommonJS

Example
// ES Modules (ESM) - Modern approach
// math.mjs
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;

// Default export
export default class Calculator {
    constructor() {
        this.history = [];
    }
    
    calculate(operation, a, b) {
        const result = operation(a, b);
        this.history.push({ operation: operation.name, a, b, result });
        return result;
    }
}

// app.mjs - Importing ES modules
import { add, subtract } from './math.mjs';
import Calculator from './math.mjs';

const calc = new Calculator();
console.log(calc.calculate(add, 5, 3)); // 8

// CommonJS - Traditional approach
// math.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;

module.exports = { add, subtract };

// app.js - Importing CommonJS
const { add, subtract } = require('./math');
console.log(add(5, 3)); // 8

// Using both in the same project
// package.json
{
  "type": "module",  // Enable ES modules
  "scripts": {
    "start": "node app.mjs"
  }
}

NPM Scripts and Automation

Example
// package.json with comprehensive scripts
{
  "name": "my-node-app",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node src/index.js",
    "dev": "nodemon src/index.js",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "lint": "eslint src/**/*.js",
    "lint:fix": "eslint src/**/*.js --fix",
    "build": "webpack --mode production",
    "build:dev": "webpack --mode development",
    "clean": "rimraf dist",
    "precommit": "npm run lint && npm run test",
    "deploy": "npm run build && npm run test && pm2 start ecosystem.config.js",
    "logs": "pm2 logs",
    "restart": "pm2 restart all"
  },
  "dependencies": {
    "express": "^4.18.2",
    "cors": "^2.8.5",
    "helmet": "^6.0.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.22",
    "jest": "^29.0.0",
    "eslint": "^8.0.0",
    "webpack": "^5.0.0",
    "rimraf": "^3.0.2",
    "pm2": "^5.0.0"
  }
}

// Custom script example
// scripts/setup.js
import fs from 'fs';
import path from 'path';

const setupProject = () => {
    const dirs = ['src', 'tests', 'docs', 'logs'];
    
    dirs.forEach(dir => {
        if (!fs.existsSync(dir)) {
            fs.mkdirSync(dir, { recursive: true });
            console.log(`Created directory: ${dir}`);
        }
    });
    
    // Create basic files
    const files = {
        'src/index.js': 'console.log("Hello from Node.js!");',
        'tests/index.test.js': 'import { test } from "jest";

test("basic test", () => {
  expect(1 + 1).toBe(2);
});',
        '.gitignore': 'node_modules/
.env
logs/
dist/',
        '.env.example': 'PORT=3000
NODE_ENV=development'
    };
    
    Object.entries(files).forEach(([filePath, content]) => {
        if (!fs.existsSync(filePath)) {
            fs.writeFileSync(filePath, content);
            console.log(`Created file: ${filePath}`);
        }
    });
    
    console.log('Project setup complete!');
};

setupProject();

Mini-Project: Module-based Calculator

Example
// Create a comprehensive calculator using modules
// src/calculator/operations.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;
export const divide = (a, b) => {
    if (b === 0) throw new Error('Division by zero');
    return a / b;
};

export const power = (a, b) => Math.pow(a, b);
export const sqrt = (a) => {
    if (a < 0) throw new Error('Square root of negative number');
    return Math.sqrt(a);
};

// src/calculator/history.js
class History {
    constructor() {
        this.operations = [];
    }
    
    add(operation, a, b, result) {
        this.operations.push({
            id: Date.now(),
            operation,
            operands: { a, b },
            result,
            timestamp: new Date().toISOString()
        });
    }
    
    getAll() {
        return this.operations;
    }
    
    getLast(n = 5) {
        return this.operations.slice(-n);
    }
    
    clear() {
        this.operations = [];
    }
    
    export() {
        return JSON.stringify(this.operations, null, 2);
    }
}

export default History;

// src/calculator/validator.js
export const validateNumber = (num) => {
    if (typeof num !== 'number' || isNaN(num)) {
        throw new Error('Invalid number provided');
    }
    return true;
};

export const validateOperation = (op) => {
    const validOps = ['add', 'subtract', 'multiply', 'divide', 'power', 'sqrt'];
    if (!validOps.includes(op)) {
        throw new Error(`Invalid operation: ${op}`);
    }
    return true;
};

// src/calculator/index.js
import * as operations from './operations.js';
import History from './history.js';
import { validateNumber, validateOperation } from './validator.js';

class Calculator {
    constructor() {
        this.history = new History();
    }
    
    calculate(operation, a, b = null) {
        try {
            validateOperation(operation);
            validateNumber(a);
            if (b !== null) validateNumber(b);
            
            let result;
            switch (operation) {
                case 'add':
                    result = operations.add(a, b);
                    break;
                case 'subtract':
                    result = operations.subtract(a, b);
                    break;
                case 'multiply':
                    result = operations.multiply(a, b);
                    break;
                case 'divide':
                    result = operations.divide(a, b);
                    break;
                case 'power':
                    result = operations.power(a, b);
                    break;
                case 'sqrt':
                    result = operations.sqrt(a);
                    break;
            }
            
            this.history.add(operation, a, b, result);
            return result;
            
        } catch (error) {
            console.error('Calculation error:', error.message);
            throw error;
        }
    }
    
    getHistory() {
        return this.history.getAll();
    }
    
    getLastOperations(n = 5) {
        return this.history.getLast(n);
    }
    
    clearHistory() {
        this.history.clear();
    }
    
    exportHistory() {
        return this.history.export();
    }
}

export default Calculator;

// src/index.js - Main application
import Calculator from './calculator/index.js';

const calc = new Calculator();

// Example usage
try {
    console.log('Calculator Demo');
    console.log('==============');
    
    console.log('5 + 3 =', calc.calculate('add', 5, 3));
    console.log('10 - 4 =', calc.calculate('subtract', 10, 4));
    console.log('6 * 7 =', calc.calculate('multiply', 6, 7));
    console.log('15 / 3 =', calc.calculate('divide', 15, 3));
    console.log('2 ^ 8 =', calc.calculate('power', 2, 8));
    console.log('√16 =', calc.calculate('sqrt', 16));
    
    console.log('\nLast 3 operations:');
    console.log(calc.getLastOperations(3));
    
    console.log('\nFull history:');
    console.log(calc.exportHistory());
    
} catch (error) {
    console.error('Error:', error.message);
}

Additional Resources

Recommended Reading

  • Node.js Official Documentation
  • Understanding the Node.js Event Loop
  • Node.js Module System Guide

Online Resources

  • Node.js Tutorial for Beginners
  • Asynchronous JavaScript Patterns
  • NPM Package Management Guide
Chat on WhatsApp
Priygop - Leading Professional Development Platform | Expert Courses & Interview Prep