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.
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
| Feature | CommonJS | ES Modules |
|---|---|---|
| Import | require() | import |
| Export | module.exports | export |
| Official JS Standard | No | Yes |
| Browser Support | No | Yes |
| Node.js Support | Yes | Yes |
| Static Analysis | Limited | Excellent |
| Tree Shaking | Poor | Excellent |
| Modern Usage | Declining | Growing |
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 expressand 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 -vExample output:
11.0.0Check Node version:
node -vOutput:
v24.0.0Creating a Node.js Project
Suppose we start building AQAD Backend.
Create project folder:
mkdir aqad-backendMove into folder:
cd aqad-backendInitialize NPM:
npm initNPM asks questions.
Example:
package name:
version:
description:
author:
license:After completion:
package.jsonis 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 -yAutomatically generates:
{
"name": "project",
"version": "1.0.0"
}Most developers use this approach.
Installing Packages
Let's install Express.
npm install expressor
npm i expressNPM downloads package files.
After installation:
node_modules
package.json
package-lock.jsonappear.
Understanding node_modules
Many beginners panic when they see:
node_modulesbecause it becomes huge.
Sometimes:
500 MB
1000 MB
2000 MBWhy?
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 expressYou think:
1 packageReality:
Dozens of packagesbecause Express depends on many internal libraries.
Dependencies
A dependency is a package your application needs.
Example:
npm install expresspackage.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-devor
npm i -D nodemonpackage.json:
{
"devDependencies": {
"nodemon": "^3.0.0"
}
}Dependencies vs Dev Dependencies
| Type | Used In Production | Used During Development |
|---|---|---|
| dependencies | Yes | Yes |
| devDependencies | No | Yes |
AQAD Example
Production dependency:
Express
JWT
AWS SDK
DynamoDB ClientDevelopment dependency:
Nodemon
ESLint
PrettierUnderstanding package-lock.json
After installing packages:
package-lock.jsonappears automatically.
Many beginners delete it.
Don't.
What Does It Do?
Imagine AQAD orders:
100 Coca-Cola BottlesNext 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 Serverall 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.PATCHExample:
2.4.7Major Version
3.0.0Breaking changes.
May require code modifications.
Minor Version
2.5.0New features.
Usually backward compatible.
Patch Version
2.4.8Bug fixes.
No major changes.
Example
1.0.0↓
1.1.0New feature added.
↓
1.1.1Bug fixed.
↓
2.0.0Breaking change introduced.
Understanding the Caret (^)
Example:
{
"express": "^5.0.0"
}Means:
5.x.xis acceptable.
But:
6.0.0is not.
Understanding the Tilde (~)
Example:
{
"express": "~5.0.0"
}Allows:
5.0.xOnly patch updates.
More restrictive.
Installing Specific Versions
Example:
npm install express@5.0.0Useful in production systems.
Removing Packages
Remove package:
npm uninstall expressNPM updates:
package.json
package-lock.jsonautomatically.
Updating Packages
Check outdated packages:
npm outdatedUpdate packages:
npm updateNPM Scripts
One of the most powerful features.
Inside package.json:
{
"scripts": {
"start": "node app.js"
}
}Run:
npm startInstead of:
node app.jsAQAD Example
{
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"test": "jest"
}
}Commands:
npm run devnpm testWhy Scripts Are Powerful
Every developer runs the same commands.
No confusion.
No documentation issues.
No manual setup.
Installing Packages Globally
Local install:
npm install nodemonOnly available in project.
Global install:
npm install -g nodemonAvailable system-wide.
Publishing Packages
NPM isn't only for consuming packages.
You can publish your own.
Imagine AQAD builds:
aqad-payment-sdkOther developers can install:
npm install aqad-payment-sdkThis is how the ecosystem grows.
Common Beginner Mistakes
Mistake 1
Committing node_modules
Bad:
Git Repository
└── node_modulesHuge repository.
Never do this.
Always add:
node_modulesto:
.gitignoreMistake 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 -yInspect package.json.
Exercise 2
Install:
npm install expressObserve:
node_modules
package.json
package-lock.jsonExercise 3
Install:
npm install nodemon --save-devCheck devDependencies.
Exercise 4
Create a script:
"dev": "node app.js"Run:
npm run devTry It Yourself
Create:
aqad-backendInitialize:
npm init -yInstall:
npm install expressInstall development tools:
npm install nodemon --save-devAdd scripts:
{
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
}
}Run:
npm run devObserve 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
ESLintManaging 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:
fswhich 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.jpgHere:
Files:
app.js
products.json
vendors.json
image1.jpgDirectories (Folders):
uploadsThe fs module helps us manage both.
Reading Files
One of the most common tasks.
Suppose we have:
products.txt
Rice
Sugar
Milk
CoffeeAsynchronous 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
CoffeeUnderstanding 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.csvBackend 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 CreatedGenerated file:
report.txt
Total Orders: 500Important Behavior
If file exists:
report.txtNode.js replaces its content.
Example:
Current file:
500 OrdersNew write:
1000 OrdersResult:
1000 OrdersOld 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 InAQAD Example
Every time an order is placed:
Order #1001 Createdappend 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:
uploadsfolder appears.
AQAD Example
Vendor uploads documents.
Create folder:
uploads/vendorsbefore saving files.
Creating Nested Directories
Example:
fs.mkdir(
'uploads/vendors',
{ recursive: true },
(err) => {}
);Output:
uploads
└── vendorsChecking Whether a File Exists
Before reading:
const fs = require('fs');
if(
fs.existsSync(
'products.txt'
)
){
console.log(
'File Found'
);
}Output:
File FoundWhy This Matters
Imagine:
invoice.pdfdoesn't exist.
Trying to read it causes an error.
Checking first prevents crashes.
Renaming Files
Suppose AQAD receives:
upload123.jpgWe want:
product-image.jpgUse:
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:
DeletedAQAD Example
Vendor deletes a product.
Remove:
product-image.jpgfrom 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.jpgRead 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.logConfiguration
config.jsonData Export
reports.csvTemporary Storage
Uploaded files before processing.
AQAD Marketplace Example
Vendor uploads:
trade-license.pdfBackend:
Step 1
Create folder.
uploads/vendor-documentsStep 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:
__dirnameor Path module.
Mistake 4
Deleting Files Without Verification
Always check existence before deletion.
Mini Exercises
Exercise 1
Create:
message.txtRead it using:
fs.readFile()Exercise 2
Create:
report.txtusing:
fs.writeFile()Exercise 3
Append:
Order Createdto:
orders.logExercise 4
Read all files inside:
uploadsusing:
fs.readdir()Try It Yourself
Create:
project
│
├── app.js
├── notes.txtnotes.txt
Node.js Learningapp.js
const fs =
require('fs');
fs.readFile(
'notes.txt',
'utf8',
(err, data) => {
console.log(data);
}
);Run:
node app.jsObserve 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:
WarehouseDubaiProductsElectronicsMobilePhonesLooks 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\uploadsLinux uses:
/Projects/AQAD/uploadsMacOS uses:
/Projects/AQAD/uploadsNotice 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.jpgOutput on Linux:
/aqad/uploads/products/image.jpgNode.js automatically chooses the correct separator.
Real-Life Analogy
Imagine GPS navigation.
Instead of manually writing:
Dubai > Warehouse > Electronics > Mobilesyou 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.jpgPath:
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\uploadsWhat Does resolve() Do?
It converts relative paths into absolute paths.
Relative Path
uploadsRelative to current location.
Absolute Path
C:\Projects\AQAD\uploadsComplete location.
Real-Life Analogy
Relative address:
Go to the nearby supermarket.Absolute address:
Building 10,
Main Road,
Dubai,
UAEMore precise.
More reliable.
Difference Between join() and resolve()
Many beginners confuse them.
path.join()
Combines path segments.
path.join(
'uploads',
'products'
);Output:
uploads/productspath.resolve()
Returns complete absolute path.
path.resolve(
'uploads',
'products'
);Output:
C:/Projects/uploads/productsUnderstanding path.basename()
Suppose we have:
uploads/products/mobile.jpgWe want only:
mobile.jpgUse:
const path = require('path');
const fileName =
path.basename(
'/uploads/products/mobile.jpg'
);
console.log(fileName);Output:
mobile.jpgAQAD Example
Vendor uploads:
trade-license.pdfStored path:
/uploads/vendor-docs/trade-license.pdfNeed only filename:
path.basename(filePath);Result:
trade-license.pdfUnderstanding path.dirname()
Sometimes we need the directory only.
Example:
/uploads/products/mobile.jpgGet folder:
const folder =
path.dirname(
'/uploads/products/mobile.jpg'
);
console.log(folder);Output:
/uploads/productsReal-Life Analogy
File:
Room 305Directory:
Building Adirname() returns the building.
Understanding path.extname()
One of the most useful methods for file uploads.
Suppose:
mobile.jpgNeed extension:
.jpgUse:
const extension =
path.extname(
'mobile.jpg'
);
console.log(extension);Output:
.jpgWhy Is This Useful?
Suppose AQAD allows only:
.jpg
.png
.webpimages.
When vendor uploads:
virus.exewe 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.jpgUnderstanding path.isAbsolute()
Checks whether a path is absolute.
Example:
console.log(
path.isAbsolute(
'/uploads'
)
);Output:
trueExample:
console.log(
path.isAbsolute(
'uploads'
)
);Output:
falseReal AQAD Upload Example
Imagine vendor uploads:
iphone.jpgWe want:
- Correct folder path
- File extension validation
- 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.pdfBackend 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.jsObserve 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.

0 Comments