Ticker

6/recent/ticker-posts

CommonJS vs ES Modules – Understanding Node.js Module Systems

 

Introduction: Two Languages Inside the Same Company

Imagine AQAD started its journey in 2018.

At that time, all employees communicated using English.

Every document, report, and process followed English.

The company grew successfully.

Years later, AQAD expanded globally.

Now many international partners preferred another communication standard.

Instead of forcing everyone to use the old system forever, AQAD began supporting both systems.

Old employees continued using the original approach.

New employees adopted the newer approach.

For a period of time, both systems existed together.

This is exactly what happened in Node.js.

For many years Node.js used:

CommonJS

const fs = require('fs');
module.exports = {};

Later JavaScript introduced a modern module system: 

ES Modules (ESM)

import fs from 'fs';

export default {};

Today every Node.js developer must understand both.

Because in real projects you will encounter:

  • Old Node.js applications using CommonJS
  • Modern applications using ES Modules
  • Libraries supporting both systems
  • Migration projects converting from CommonJS to ES Modules

Before becoming a backend developer, you need to understand why both exist and when to use each one.

CommonJS vs ES Modules – Understanding Node.js Module Systems




The Problem Before Modules Existed

Let's go back to the early days of JavaScript.

Developers often included files directly in HTML:

<script src="user.js"></script>

<script src="product.js"></script>

<script src="order.js"></script>

This worked for small applications.

But large applications faced problems.


Problem 1: Global Variable Pollution

user.js

var name = "Ahmed";

product.js

var name = "iPhone";

Which value should JavaScript use?

Nobody knows.

Variables start colliding.


Problem 2: Dependency Management

Suppose:

product.js

depends on:

database.js

If files load in the wrong order:

<script src="product.js"></script>

<script src="database.js"></script>

Application breaks.


Problem 3: Maintainability

As projects grow:

50 Files

100 Files

500 Files

Managing dependencies becomes difficult.

Developers needed a better solution.


Birth of CommonJS

When Node.js was created in 2009, JavaScript had no official module system.

Ryan Dahl needed a solution.

The Node.js community adopted:

CommonJS

It became the standard module system for Node.js.


What Is CommonJS?

CommonJS is the original module system used by Node.js.

It introduced two major concepts:

Export

Share code.

Require

Import code.


CommonJS Example

math.js

function add(a, b) {
return a + b;
}

module.exports = add;

app.js

const add = require('./math');

console.log(add(5, 10));

Output:

15

Simple.

Powerful.

Easy to understand.

This became the foundation of Node.js development.


How CommonJS Works Internally

When Node.js encounters:

require('./math');

it performs these steps:

Step 1

Locate file.


Step 2

Read file.


Step 3

Wrap file inside a function.

Internally Node.js does something similar:

(function (
exports,
require,
module,
__filename,
__dirname
) {

// module code

});

Step 4

Execute code.


Step 5

Return exported value.


This wrapping mechanism explains why:

module
exports
require
__dirname
__filename

are available inside every CommonJS module.


Why CommonJS Became Popular

At the time it solved many problems.

Benefits:

Simplicity

Easy syntax.

require()

Reusability

Modules could easily share functionality.


Encapsulation

Variables stayed inside modules.


Better Project Structure

Large applications became manageable.


Limitations of CommonJS

As JavaScript evolved, developers discovered limitations.


Limitation 1: Synchronous Loading

CommonJS loads modules synchronously.

const user = require('./user');

Node waits until loading completes.

For server-side development this is acceptable.

For browsers it can be inefficient.


Limitation 2: Not Native JavaScript

CommonJS was created by the community.

Not by the JavaScript language itself.


Limitation 3: Browser Compatibility

Browsers did not natively understand:

require()

Extra tools became necessary.

Examples:

  • Webpack
  • Browserify
  • Rollup

The JavaScript ecosystem needed an official standard.


Birth of ES Modules

In 2015, JavaScript introduced:

ECMAScript 6 (ES6)

One major feature was:

ES Modules (ESM)

For the first time, JavaScript officially supported modules.


What Are ES Modules?

ES Modules are the official module system of JavaScript.

Instead of:

require()

we use:

import

Instead of:

module.exports

we use:

export

Your First ES Module

math.js

export function add(a, b) {
return a + b;
}

app.js

import { add } from './math.js';

console.log(add(5, 10));

Output:

15

Same result.

Different syntax.


Exporting in ES Modules

There are multiple ways.


Named Export

math.js

export function add() {}

export function subtract() {}

Import:

import {
add,
subtract
} from './math.js';

Default Export

Sometimes a module exposes only one main item.

Example:

export default function add() {
}

Import:

import add from './math.js';

Notice:

No curly braces.


AQAD Example

Imagine:

paymentService.js

contains a single payment processor.


Export:

export default processPayment;

Import:

import processPayment
from './paymentService.js';

This is very common in modern projects.


Multiple Named Exports

userService.js

export function createUser() {}

export function updateUser() {}

export function deleteUser() {}

Import:

import {
createUser,
updateUser,
deleteUser
}
from './userService.js';

This pattern is heavily used in enterprise applications.


CommonJS vs ES Modules Syntax

CommonJS

const fs = require('fs');

module.exports = {};

ES Modules

import fs from 'fs';

export default {};

Same goal.

Different syntax.


Enabling ES Modules in Node.js

Node.js originally supported only CommonJS.

To use ES Modules, we must tell Node.js.


Method 1: package.json

{
"type": "module"
}

Now Node treats files as ES Modules.


Example

package.json

{
"type": "module"
}

math.js

export function add(a, b) {
return a + b;
}

app.js

import { add }
from './math.js';

Works correctly.


Important Difference: File Extensions

CommonJS:

require('./math');

Often works without extension.


ES Modules:

import { add }
from './math.js';

Extension is required.

This surprises many beginners.


CommonJS Export Example

user.js

module.exports = {
getUser() {},
createUser() {}
};

Import:

const user =
require('./user');

ES Module Equivalent

user.js

export function getUser() {}

export function createUser() {}

Import:

import {
getUser,
createUser
}
from './user.js';

Much cleaner and easier to read.


CommonJS vs ES Modules Comparison

FeatureCommonJSES Modules
Importrequire()import
Exportmodule.exportsexport
Official JS StandardNoYes
Browser SupportNoYes
Node.js SupportYesYes
Static AnalysisLimitedExcellent
Tree ShakingPoorExcellent
Modern UsageDecliningGrowing

What Is Tree Shaking?

Imagine AQAD ships a package containing:

100 Products

Retailer only needs:

10 Products

Would you deliver all 100?

No.

You send only what's required.

Tree shaking works similarly.

ES Modules allow build tools to remove unused code.

Result:

  • Smaller bundles
  • Faster applications
  • Better performance

CommonJS in Real Backend Projects

Many production Node.js systems still use:

require()
module.exports

Why?

Because:

  • Stable
  • Mature
  • Large existing codebases

Many companies built applications years before ES Modules existed.


ES Modules in Modern Projects

New projects increasingly use:

import
export

because:

  • Standard JavaScript
  • Better tooling
  • Better optimization
  • Cleaner syntax

AQAD Example

Suppose AQAD starts today.

A modern architecture might use:

import express from 'express';

import userRoutes
from './routes/userRoutes.js';

import orderRoutes
from './routes/orderRoutes.js';

This follows current industry trends.


Mixing CommonJS and ES Modules

Beginners often attempt:

import express
from 'express';

module.exports = {};

Bad idea.

Mixing systems creates confusion.

Choose one approach per project.


Common Beginner Mistakes

Mistake 1

Forgetting "type": "module"

import fs from 'fs';

Error appears.

Why?

Node still expects CommonJS.


Mistake 2

Missing File Extension

Bad:

import user
from './user';

Good:

import user
from './user.js';

Mistake 3

Using require Inside ES Module

Bad:

import express
from 'express';

const fs = require('fs');

Avoid mixing.


Mistake 4

Confusing Default and Named Exports

Export:

export default add;

Import:

import add from './math.js';

Not:

import { add }
from './math.js';

Mini Exercises

Exercise 1

Create:

export function greet() {}

Import it into another file.


Exercise 2

Create:

export default function multiply() {}

Import and execute it.


Exercise 3

Convert a CommonJS module into an ES Module.


Exercise 4

Create:

userService.js

with:

createUser()

deleteUser()

updateUser()

Import all three.


Try It Yourself

Create:

package.json

{
"type": "module"
}

math.js

export function add(a, b) {
return a + b;
}

export function multiply(a, b) {
return a * b;
}

app.js

import {
add,
multiply
}
from './math.js';

console.log(add(5, 5));

console.log(multiply(5, 5));

Run:

node app.js

Observe how ES Modules work.


Real Industry Recommendation

If you are maintaining an old Node.js application:

Use CommonJS.

If you are starting a new project today:

Prefer ES Modules.

Most modern frameworks and tools are moving toward:

import
export

as the standard approach.

Learning both is important because you will encounter both throughout your backend career.


NPM Deep Dive – Understanding the World's Largest Software Library


Introduction: Imagine Building AQAD Without Suppliers

Let's imagine a strange situation.

AQAD launches a new marketplace.

Retailers open the app and search for products.

But there is a problem.

There are no suppliers.

No vendors.

No manufacturers.

No distributors.

Every single product must be created by AQAD itself.

Need rice?

Produce it yourself.

Need milk?

Create your own dairy farm.

Need soft drinks?

Build your own beverage factory.

Need electronics?

Open your own manufacturing plant.

Very quickly the business becomes impossible to scale.

Now let's compare this to software development.

Imagine building a Node.js application.

Need authentication?

Write everything from scratch.

Need password encryption?

Write your own algorithm.

Need JWT authentication?

Build your own token system.

Need file uploads?

Create everything manually.

Need email functionality?

Develop your own email protocol.

Need database connectivity?

Build your own database driver.

Sounds crazy, right?

This is exactly why NPM exists.

NPM gives developers access to millions of reusable packages created by other developers.

Instead of reinventing the wheel, we can use trusted solutions and focus on solving business problems.

Without NPM, Node.js would never have become as popular as it is today.


What Is NPM?

NPM stands for:

Node Package Manager

However, modern developers usually think of NPM as three things:

1. A Website

A marketplace of packages.

2. A Registry

A huge database storing packages.

3. A Command Line Tool

Used to install and manage packages.

Think of it like Amazon for software.

Instead of buying physical products, developers download code packages.


Why NPM Was Created

Before package managers existed, sharing code was difficult.

Developers would:

  • Copy files manually
  • Download ZIP archives
  • Email source code
  • Store reusable code in random folders

This created many problems:

  • Version conflicts
  • Missing files
  • Difficult updates
  • Dependency chaos

NPM solved these issues by creating a centralized ecosystem.


What Is a Package?

A package is simply reusable code.

Examples:

Express

Creates APIs and web servers.

Mongoose

Connects to MongoDB.

Axios

Makes HTTP requests.

JWT

Creates authentication tokens.

Nodemailer

Sends emails.


Instead of writing thousands of lines yourself:

npm install express

and much of the work is already done.


The Scale of NPM

NPM is considered one of the largest software registries in the world.

Millions of packages exist.

Every day:

  • Developers publish packages
  • Developers update packages
  • Companies maintain packages
  • Applications install packages

Most modern Node.js applications depend on dozens or even hundreds of packages.


First Look at NPM

Check NPM version:

npm -v

Example output:

11.0.0

Check Node version:

node -v

Output:

v24.0.0

Creating a Node.js Project

Suppose we start building AQAD Backend.

Create project folder:

mkdir aqad-backend

Move into folder:

cd aqad-backend

Initialize NPM:

npm init

NPM asks questions.


Example:

package name:
version:
description:
author:
license:

After completion:

package.json

is created.


Understanding package.json

This is one of the most important files in any Node.js project.

Think of package.json as:

The Identity Card of Your Application

It contains:

  • Project name
  • Version
  • Dependencies
  • Scripts
  • Author information
  • Project configuration

Example:

{
"name": "aqad-backend",
"version": "1.0.0",
"description": "AQAD Marketplace API",
"main": "app.js"
}

Why package.json Matters

Imagine a new developer joins AQAD.

Without package.json:

Nobody knows:

  • Which packages are required
  • Which versions are needed
  • How to start the project

With package.json:

Everything is documented.


Quick Initialization

Instead of answering questions:

npm init -y

Automatically generates:

{
"name": "project",
"version": "1.0.0"
}

Most developers use this approach.


Installing Packages

Let's install Express.

npm install express

or

npm i express

NPM downloads package files.


After installation:

node_modules
package.json
package-lock.json

appear.


Understanding node_modules

Many beginners panic when they see:

node_modules

because it becomes huge.

Sometimes:

500 MB

1000 MB

2000 MB

Why?

Because packages have dependencies.

Those dependencies have dependencies.

Those dependencies have dependencies.

It creates a dependency tree.


Real-Life Analogy

Suppose AQAD buys products from a vendor.

That vendor depends on:

  • Manufacturers

Manufacturers depend on:

  • Raw material suppliers

Suppliers depend on:

  • Transport companies

The chain grows larger and larger.

The same happens inside node_modules.


Example

Install:

npm install express

You think:

1 package

Reality:

Dozens of packages

because Express depends on many internal libraries.


Dependencies

A dependency is a package your application needs.

Example:

npm install express

package.json becomes:

{
"dependencies": {
"express": "^5.0.0"
}
}

This means:

The project requires Express.


Development Dependencies

Some packages are only needed during development.

Examples:

  • Nodemon
  • ESLint
  • Prettier
  • Jest

Install:

npm install nodemon --save-dev

or

npm i -D nodemon

package.json:

{
"devDependencies": {
"nodemon": "^3.0.0"
}
}

Dependencies vs Dev Dependencies

TypeUsed In Production     Used During Development
dependenciesYes              Yes
devDependenciesNo       Yes

AQAD Example

Production dependency:

Express
JWT
AWS SDK
DynamoDB Client

Development dependency:

Nodemon
ESLint
Prettier

Understanding package-lock.json

After installing packages:

package-lock.json

appears automatically.

Many beginners delete it.

Don't.


What Does It Do?

Imagine AQAD orders:

100 Coca-Cola Bottles

Next month:

Vendor sends a slightly different version.

Now inventory behaves differently.

Problems begin.


Similarly:

Package versions can change.

package-lock.json locks exact versions.

This ensures:

Developer A

Developer B

Production Server

all use identical package versions.


Example

package.json:

{
"express": "^5.0.0"
}

The caret:

^

allows minor updates.

package-lock.json records the exact version installed.


Semantic Versioning (SemVer)

Almost every package follows:

MAJOR.MINOR.PATCH

Example:

2.4.7

Major Version

3.0.0

Breaking changes.

May require code modifications.


Minor Version

2.5.0

New features.

Usually backward compatible.


Patch Version

2.4.8

Bug fixes.

No major changes.


Example

1.0.0

1.1.0

New feature added.

1.1.1

Bug fixed.

2.0.0

Breaking change introduced.


Understanding the Caret (^)

Example:

{
"express": "^5.0.0"
}

Means:

5.x.x

is acceptable.

But:

6.0.0

is not.


Understanding the Tilde (~)

Example:

{
"express": "~5.0.0"
}

Allows:

5.0.x

Only patch updates.

More restrictive.


Installing Specific Versions

Example:

npm install express@5.0.0

Useful in production systems.


Removing Packages

Remove package:

npm uninstall express

NPM updates:

package.json
package-lock.json

automatically.


Updating Packages

Check outdated packages:

npm outdated

Update packages:

npm update

NPM Scripts

One of the most powerful features.

Inside package.json:

{
"scripts": {
"start": "node app.js"
}
}

Run:

npm start

Instead of:

node app.js

AQAD Example

{
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"test": "jest"
}
}

Commands:

npm run dev
npm test

Why Scripts Are Powerful

Every developer runs the same commands.

No confusion.

No documentation issues.

No manual setup.


Installing Packages Globally

Local install:

npm install nodemon

Only available in project.


Global install:

npm install -g nodemon

Available system-wide.


Publishing Packages

NPM isn't only for consuming packages.

You can publish your own.

Imagine AQAD builds:

aqad-payment-sdk

Other developers can install:

npm install aqad-payment-sdk

This is how the ecosystem grows.


Common Beginner Mistakes

Mistake 1

Committing node_modules

Bad:

Git Repository
└── node_modules

Huge repository.

Never do this.


Always add:

node_modules

to:

.gitignore

Mistake 2

Deleting package-lock.json

Many beginners remove it.

Keep it.

It ensures consistent installations.


Mistake 3

Installing Everything Globally

Bad habit.

Most packages should remain project-specific.


Mistake 4

Ignoring Version Changes

Updating blindly can break applications.

Always review major version upgrades.


Mini Exercises

Exercise 1

Create a new project.

Run:

npm init -y

Inspect package.json.


Exercise 2

Install:

npm install express

Observe:

node_modules
package.json
package-lock.json

Exercise 3

Install:

npm install nodemon --save-dev

Check devDependencies.


Exercise 4

Create a script:

"dev": "node app.js"

Run:

npm run dev

Try It Yourself

Create:

aqad-backend

Initialize:

npm init -y

Install:

npm install express

Install development tools:

npm install nodemon --save-dev

Add scripts:

{
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
}
}

Run:

npm run dev

Observe how NPM simplifies project management.


Real AQAD Example

A production AQAD backend may have:

Express
JWT
AWS SDK
Multer
Bcrypt
Helmet
Morgan
Joi
Winston
Nodemon
ESLint

Managing all of these manually would be impossible.

NPM becomes the warehouse manager of the entire software supply chain.



The File System (fs) Module – How Node.js Reads and Writes Files


Introduction: Imagine AQAD Without a Warehouse

Let's imagine AQAD has become a successful B2B marketplace.

Every day:

  • Vendors upload products
  • Retailers place orders
  • Logistics partners update deliveries
  • Employees generate reports

Now imagine something strange.

AQAD has no warehouse.

Every product arrives and immediately disappears.

No storage.

No records.

No inventory.

No invoices.

No product images.

No vendor documents.

No delivery proofs.

The business would collapse within days.

Why?

Because businesses need a place to store information.

Computers work the same way.

Applications constantly need to:

  • Save files
  • Read files
  • Update files
  • Delete files

Node.js provides a built-in module called:

fs

which stands for:

File System

Think of it as the warehouse manager of your application.

It helps Node.js interact with files stored on your computer or server.

Almost every backend application uses the File System module in some way.

Examples:

  • Uploading profile pictures
  • Saving product images
  • Generating reports
  • Storing logs
  • Reading configuration files
  • Processing CSV imports
  • Handling invoices and PDFs

Understanding the File System module is an important step toward becoming a professional backend developer.


What Is the File System Module?

The File System module allows Node.js to work with files and folders.

Unlike browsers, Node.js can directly access the operating system.

This means Node.js can:

  • Create files
  • Read files
  • Update files
  • Delete files
  • Create directories
  • Remove directories

Importing the File System Module

Since fs is a built-in Node.js module:

const fs = require('fs');

No installation needed.

No npm package required.

Node.js already includes it.


Understanding Files and Directories

Before writing code, let's understand the terminology.

Example:

AQAD

├── app.js
├── products.json
├── vendors.json

└── uploads
├── image1.jpg
└── image2.jpg

Here:

Files:

app.js
products.json
vendors.json
image1.jpg

Directories (Folders):

uploads

The fs module helps us manage both.


Reading Files

One of the most common tasks.

Suppose we have:

products.txt

Rice
Sugar
Milk
Coffee

Asynchronous Reading

const fs = require('fs');

fs.readFile(
'products.txt',
'utf8',
(error, data) => {

if(error){
console.log(error);
return;
}

console.log(data);

}
);

Output:

Rice
Sugar
Milk
Coffee

Understanding the Parameters

fs.readFile(
path,
encoding,
callback
);

Path

Location of file.

'products.txt'

Encoding

How file should be interpreted.

'utf8'

Most text files use UTF-8.


Callback

Runs after file reading finishes.

(error, data) => {}

Why ReadFile Is Asynchronous

Imagine a warehouse worker.

A manager says:

Bring me the inventory report.

The worker leaves.

The manager continues working.

He doesn't stand still waiting.

Later the worker returns with the report.

That's asynchronous behavior.

Node.js works exactly like this.


AQAD Example

Suppose vendors upload:

vendor-products.csv

Backend reads file:

fs.readFile(
'vendor-products.csv',
'utf8',
(err, data) => {
console.log(data);
}
);

The server can continue handling requests while the file loads.


Synchronous Reading

Node.js also provides:

fs.readFileSync()

Example:

const fs = require('fs');

const data =
fs.readFileSync(
'products.txt',
'utf8'
);

console.log(data);

What Happens Here?

Node.js stops everything.

It waits.

Only after file reading completes:

console.log(data);

runs.


Real-Life Analogy

Asynchronous:

Manager continues working while assistant gets report.


Synchronous:

Manager freezes.

Does nothing.

Waits for report.

Then continues.


Which One Should You Use?

Backend applications generally prefer:

fs.readFile()

because it is non-blocking.

Use synchronous methods only for:

  • Startup configurations
  • Small scripts
  • Development tools

Writing Files

Suppose AQAD wants to generate a sales report.

We need to create a file.


Using writeFile()

const fs = require('fs');

fs.writeFile(
'report.txt',
'Total Orders: 500',
(error) => {

if(error){
console.log(error);
return;
}

console.log(
'File Created'
);

}
);

Output:

File Created

Generated file:

report.txt

Total Orders: 500

Important Behavior

If file exists:

report.txt

Node.js replaces its content.

Example:

Current file:

500 Orders

New write:

1000 Orders

Result:

1000 Orders

Old content disappears.


Appending Data

Sometimes we want to add data instead of replacing it.

Use:

fs.appendFile()

Example:

fs.appendFile(
'logs.txt',
'\nUser Logged In',
(err) => {
console.log('Updated');
}
);

File:

User Registered
User Logged In

AQAD Example

Every time an order is placed:

Order #1001 Created

append to log file.

fs.appendFile(
'orders.log',
'\nOrder #1001 Created',
() => {}
);

Useful for auditing.


Creating Directories

Many applications create folders dynamically.

Example:

fs.mkdir(
'uploads',
(err) => {
console.log(
'Folder Created'
);
}
);

Result:

uploads

folder appears.


AQAD Example

Vendor uploads documents.

Create folder:

uploads/vendors

before saving files.


Creating Nested Directories

Example:

fs.mkdir(
'uploads/vendors',
{ recursive: true },
(err) => {}
);

Output:

uploads
└── vendors

Checking Whether a File Exists

Before reading:

const fs = require('fs');

if(
fs.existsSync(
'products.txt'
)
){
console.log(
'File Found'
);
}

Output:

File Found

Why This Matters

Imagine:

invoice.pdf

doesn't exist.

Trying to read it causes an error.

Checking first prevents crashes.


Renaming Files

Suppose AQAD receives:

upload123.jpg

We want:

product-image.jpg

Use:

fs.rename(
'upload123.jpg',
'product-image.jpg',
(err) => {

console.log(
'Renamed'
);

}
);

Deleting Files

Removing files is simple.

Example:

fs.unlink(
'old-report.txt',
(err) => {

console.log(
'Deleted'
);

}
);

Output:

Deleted

AQAD Example

Vendor deletes a product.

Remove:

product-image.jpg

from storage.

fs.unlink(
imagePath,
() => {}
);

Removing Directories

Modern Node.js:

fs.rm(
'uploads',
{
recursive: true
},
(err) => {

console.log(
'Removed'
);

}
);

Deletes entire folder structure.


Reading Directory Contents

Suppose:

uploads

├── image1.jpg
├── image2.jpg
├── image3.jpg

Read contents:

fs.readdir(
'uploads',
(err, files) => {

console.log(files);

}
);

Output:

[
'image1.jpg',
'image2.jpg',
'image3.jpg'
]

Getting File Information

Use:

fs.stat()

Example:

fs.stat(
'products.txt',
(err, stats) => {

console.log(stats);

}
);

Output contains:

  • File size
  • Creation date
  • Modification date

Useful for uploads.


AQAD Example

Check uploaded file size:

fs.stat(
imagePath,
(err, stats) => {

console.log(
stats.size
);

}
);

Prevent huge files from being stored.


Understanding File Paths

Many beginner bugs come from paths.

Bad:

fs.readFile(
'products.txt'
);

Works only if current directory is correct.


Better:

fs.readFile(
__dirname +
'/products.txt'
);

Now Node always knows the exact location.


Common Real-World Usage

Most backend systems use fs for:


File Uploads

Images

PDFs

Documents


Logging

errors.log
orders.log

Configuration

config.json

Data Export

reports.csv

Temporary Storage

Uploaded files before processing.


AQAD Marketplace Example

Vendor uploads:

trade-license.pdf

Backend:

Step 1

Create folder.

uploads/vendor-documents

Step 2

Save file.

Step 3

Verify file size.

Step 4

Store path in database.

Step 5

Allow future downloads.

Every step uses the File System module.


Common Beginner Mistakes

Mistake 1

Using Sync Methods Everywhere

Bad:

fs.readFileSync()

inside APIs.

Blocks server.


Mistake 2

Ignoring Errors

Bad:

fs.readFile(
file,
(err, data) => {
console.log(data);
}
);

Always handle errors.


Mistake 3

Using Relative Paths Incorrectly

Bad:

'./file.txt'

Can fail unexpectedly.

Use:

__dirname

or Path module.


Mistake 4

Deleting Files Without Verification

Always check existence before deletion.


Mini Exercises

Exercise 1

Create:

message.txt

Read it using:

fs.readFile()

Exercise 2

Create:

report.txt

using:

fs.writeFile()

Exercise 3

Append:

Order Created

to:

orders.log

Exercise 4

Read all files inside:

uploads

using:

fs.readdir()

Try It Yourself

Create:

project

├── app.js
├── notes.txt

notes.txt

Node.js Learning

app.js

const fs =
require('fs');

fs.readFile(
'notes.txt',
'utf8',
(err, data) => {

console.log(data);

}
);

Run:

node app.js

Observe how Node.js reads files.


The Path Module – Navigating Files Like a Professional Developer


Introduction: Why Addresses Matter in a Growing Business

Imagine AQAD has warehouses in:

  • Dubai
  • Abu Dhabi
  • Sharjah
  • Ajman
  • Ras Al Khaimah

Every day thousands of products move between locations.

Now imagine someone writes an address like this:

WarehouseDubaiProductsElectronicsMobilePhones

Looks confusing, right?

Nobody knows:

  • Where the warehouse starts
  • Where the city name ends
  • Which section contains electronics
  • Which section contains mobile phones

Addresses need structure.

That's why we use:

Warehouse/
Dubai/
Products/
Electronics/
MobilePhones/

Computers face the same challenge.

Applications constantly work with:

  • Images
  • Documents
  • Reports
  • Configuration files
  • Upload folders

Node.js needs a reliable way to manage file paths.

This is where the Path Module becomes important.

Think of it as the GPS system of your backend application.

It helps Node.js locate files and folders safely and correctly.


What Is the Path Module?

The Path module is a built-in Node.js module that helps developers work with file and directory paths.

Instead of manually creating paths:

const path =
"C:\\AQAD\\uploads\\products";

Node.js provides utilities that work across different operating systems.


Why Path Module Exists

Let's look at a common problem.

Windows uses:

C:\Projects\AQAD\uploads

Linux uses:

/Projects/AQAD/uploads

MacOS uses:

/Projects/AQAD/uploads

Notice the difference?

Windows:

\

Linux and Mac:

/

If we hardcode paths:

"C:\\Projects\\AQAD\\uploads"

the application may fail on Linux.

The Path module solves this problem.


Importing the Path Module

Since it is built into Node.js:

const path = require('path');

No installation needed.


Understanding path.join()

One of the most commonly used methods.


The Problem

Beginners often write:

const filePath =
__dirname +
"/uploads/products/image.jpg";

This works sometimes.

But it can create issues across operating systems.


Better Solution

const path = require('path');

const filePath =
path.join(
__dirname,
'uploads',
'products',
'image.jpg'
);

console.log(filePath);

Output on Windows:

C:\AQAD\uploads\products\image.jpg

Output on Linux:

/aqad/uploads/products/image.jpg

Node.js automatically chooses the correct separator.


Real-Life Analogy

Imagine GPS navigation.

Instead of manually writing:

Dubai > Warehouse > Electronics > Mobiles

you provide each location separately.

The GPS combines them correctly.

That's exactly what path.join() does.


AQAD Example

Suppose vendors upload product images.

Folder structure:

uploads

└── products
└── image.jpg

Path:

const imagePath =
path.join(
__dirname,
'uploads',
'products',
'image.jpg'
);

Safe.

Readable.

Professional.


Understanding path.resolve()

Another important method.


Example

const path = require('path');

const result =
path.resolve('uploads');

console.log(result);

Output:

C:\Projects\AQAD\uploads

What Does resolve() Do?

It converts relative paths into absolute paths.


Relative Path

uploads

Relative to current location.


Absolute Path

C:\Projects\AQAD\uploads

Complete location.


Real-Life Analogy

Relative address:

Go to the nearby supermarket.

Absolute address:

Building 10,
Main Road,
Dubai,
UAE

More precise.

More reliable.


Difference Between join() and resolve()

Many beginners confuse them.


path.join()

Combines path segments.

path.join(
'uploads',
'products'
);

Output:

uploads/products

path.resolve()

Returns complete absolute path.

path.resolve(
'uploads',
'products'
);

Output:

C:/Projects/uploads/products

Understanding path.basename()

Suppose we have:

uploads/products/mobile.jpg

We want only:

mobile.jpg

Use:

const path = require('path');

const fileName =
path.basename(
'/uploads/products/mobile.jpg'
);

console.log(fileName);

Output:

mobile.jpg

AQAD Example

Vendor uploads:

trade-license.pdf

Stored path:

/uploads/vendor-docs/trade-license.pdf

Need only filename:

path.basename(filePath);

Result:

trade-license.pdf

Understanding path.dirname()

Sometimes we need the directory only.

Example:

/uploads/products/mobile.jpg

Get folder:

const folder =
path.dirname(
'/uploads/products/mobile.jpg'
);

console.log(folder);

Output:

/uploads/products

Real-Life Analogy

File:

Room 305

Directory:

Building A

dirname() returns the building.


Understanding path.extname()

One of the most useful methods for file uploads.

Suppose:

mobile.jpg

Need extension:

.jpg

Use:

const extension =
path.extname(
'mobile.jpg'
);

console.log(extension);

Output:

.jpg

Why Is This Useful?

Suppose AQAD allows only:

.jpg
.png
.webp

images.

When vendor uploads:

virus.exe

we can reject it.

Example:

const extension =
path.extname(fileName);

if(
extension !== '.jpg'
){
console.log(
'Invalid File'
);
}

Understanding path.parse()

Sometimes we need detailed information.

Example:

const result =
path.parse(
'/uploads/products/mobile.jpg'
);

console.log(result);

Output:

{
root: '/',
dir: '/uploads/products',
base: 'mobile.jpg',
ext: '.jpg',
name: 'mobile'
}

Why parse() Is Powerful

Instead of calling:

basename()
dirname()
extname()

multiple times,

one function returns everything.


Understanding path.format()

The opposite of parse().

Example:

const pathInfo = {
dir: '/uploads/products',
base: 'mobile.jpg'
};

console.log(
path.format(pathInfo)
);

Output:

/uploads/products/mobile.jpg

Understanding path.isAbsolute()

Checks whether a path is absolute.

Example:

console.log(
path.isAbsolute(
'/uploads'
)
);

Output:

true

Example:

console.log(
path.isAbsolute(
'uploads'
)
);

Output:

false

Real AQAD Upload Example

Imagine vendor uploads:

iphone.jpg

We want:

  1. Correct folder path
  2. File extension validation
  3. Full storage path

Example:

const path =
require('path');

const uploadPath =
path.join(
__dirname,
'uploads',
'products'
);

const extension =
path.extname(
'iphone.jpg'
);

if(
extension === '.jpg'
){
console.log(
uploadPath
);
}

This is very close to real production code.


Why Professional Developers Avoid String Concatenation

Bad:

const filePath =
__dirname +
'/uploads/' +
fileName;

Problems:

  • Hard to read
  • Easy to break
  • Cross-platform issues

Good:

const filePath =
path.join(
__dirname,
'uploads',
fileName
);

Cleaner.

Safer.

Industry standard.


Common Use Cases of Path Module


File Uploads

path.extname()

Validate file types.


Dynamic Folder Creation

path.join()

Generate paths safely.


Logging

path.basename()

Extract filenames.


Config Files

path.resolve()

Locate configuration files.


Report Generation

path.dirname()

Determine output folders.


AQAD Marketplace Scenario

Imagine:

Vendor uploads:

invoice.pdf

Backend performs:

Step 1

Validate extension.

path.extname()

Step 2

Build storage path.

path.join()

Step 3

Save file.


Step 4

Store path in database.


Step 5

Retrieve later for download.

Every step depends on Path module utilities.


Common Beginner Mistakes

Mistake 1

Using String Concatenation

Bad:

__dirname + '/uploads'

Prefer:

path.join()

Mistake 2

Ignoring Platform Differences

Windows:

\

Linux:

/

Path module handles this automatically.


Mistake 3

Checking File Types Incorrectly

Bad:

if(file.includes('.jpg'))

Good:

path.extname(file)

Mistake 4

Confusing join() and resolve()

Remember:

join()

Combines paths.

resolve()

Creates absolute paths.


Mini Exercises

Exercise 1

Create:

path.join(
'uploads',
'products',
'mobile.jpg'
);

Observe output.


Exercise 2

Use:

path.basename()

to extract filename.


Exercise 3

Use:

path.extname()

to detect file extension.


Exercise 4

Use:

path.resolve()

to generate an absolute path.


Try It Yourself

Create:

app.js

const path =
require('path');

console.log(
path.join(
__dirname,
'uploads',
'products',
'mobile.jpg'
)
);

console.log(
path.basename(
'mobile.jpg'
)
);

console.log(
path.extname(
'mobile.jpg'
)
);

Run:

node app.js

Observe the results.


Real Developer Insight

In real backend projects, you will almost never see:

__dirname + '/uploads'

Instead you'll constantly see:

path.join()

because experienced developers understand that applications must run correctly on:

  • Windows
  • Linux
  • MacOS
  • Docker Containers
  • Cloud Servers

The Path module ensures that happens.


Post a Comment

0 Comments