Topic 1: Introduction and Foundation
📖 7 min read · 🎯 beginner · 🧭 Prerequisites: None
Why this matters
Up until now, you've been writing JavaScript that only lives in the browser — it controls buttons, handles clicks, talks to the DOM. That's powerful, but it's only half the picture. Here's the thing — every website you use has a server behind it, handling requests, storing data, running the real logic. Node.js is what lets you write that server side in JavaScript too. The same language, a completely new superpower. By the end of this lesson, you'll have your first Node.js server running on your own machine, responding to requests — and that moment will change how you see the web.
What You'll Learn
- What Node.js is, how it works, and why its async, event-driven architecture makes it fast
- How to install Node.js and NPM and verify both are working
- How to scaffold a project, write an entry point, and run it from the terminal
- How to use core modules (
http,fs,path), install third-party modules (express), and create custom modules - How to write asynchronous code with callbacks, Promises, and async/await
The Analogy
Think of a busy café with a single skilled barista — that's Node.js. A traditional multi-threaded server is a café that hires one barista per customer: expensive, crowded, and slow to scale. Node's barista takes your order, hands it to the espresso machine (a non-blocking I/O operation), and immediately takes the next customer's order without standing idle watching the machine run. When the machine beeps, the barista comes back and finishes your drink. The result: one person serves dozens of customers at the same time, and the café never needs to hire a small army just to handle the morning rush. That's Node's event loop in a nutshell — one thread, no waiting around, massive throughput.
Chapter 1: Introduction to Node.js
Node.js is an open-source, cross-platform runtime environment that allows developers to execute JavaScript code outside of a web browser. It is built on Chrome's V8 JavaScript engine — the same engine that makes Chrome fast — and is designed specifically to build scalable network applications.
Key Features of Node.js
- Asynchronous and Event-Driven — Node.js uses a non-blocking, event-driven architecture for handling multiple requests efficiently. Operations like reading files or querying a database do not freeze the process; they register a callback and move on.
- Single-Threaded — Node.js operates on a single thread using non-blocking I/O calls, making it efficient and lightweight. The event loop manages concurrency without the overhead of thread management.
- Fast Execution — Built on the V8 JavaScript engine, Node.js compiles JavaScript directly to native machine code, executing it quickly.
- NPM (Node Package Manager) — Node.js ships with NPM, a package manager that provides access to a vast library of open-source packages — over two million and counting.
flowchart LR
Client -->|Request| EventLoop
EventLoop -->|Non-blocking I/O| FileSystem
EventLoop -->|Non-blocking I/O| Database
EventLoop -->|Non-blocking I/O| Network
FileSystem -->|Callback| EventLoop
Database -->|Callback| EventLoop
Network -->|Callback| EventLoop
EventLoop -->|Response| Client
Chapter 2: Setting Up Node.js
the trainer walked the class through installing Node.js on their machines. The official installer is available at nodejs.org and bundles both Node.js and NPM in a single package.
After installation, verify everything is working:
node -v # Check installed Node.js version
npm -v # Check installed NPM version
You should see version numbers printed for both. If you see a command not found error, revisit the installer and ensure Node is added to your system PATH.
Chapter 3: Creating a Simple Node.js Application
With Node installed, the trainer demonstrated scaffolding a project from scratch.
Step 1: Initialize a Node.js Project
mkdir my-node-app
cd my-node-app
npm init -y
The npm init -y command creates a package.json file with default settings. This file tracks your project's name, version, dependencies, and scripts — it is the heartbeat of any Node.js project.
Step 2: Create an Entry Point
Create a file named app.js in your project folder:
app.js:
console.log('Hello, Vizag!');
Step 3: Run the Application
node app.js
Output:
Hello, Vizag!
That single line confirms Node.js is executing JavaScript outside the browser. Simple — but significant.
Chapter 4: Understanding Modules
Node.js uses modules to encapsulate and organise code. There are three kinds:
- Core modules — built into Node.js itself, no installation required
- Third-party modules — installed via NPM from the public registry
- Custom modules — files you write and
require()yourself
Core Modules
Node.js ships with several powerful built-in modules:
| Module | Purpose |
|---|---|
fs | File system operations (read, write, delete files) |
http | Create web servers and handle HTTP requests |
path | Work with file and directory paths cross-platform |
Using the http Core Module
The class built their first web server:
app.js:
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, Vizag!\n');
});
const PORT = 3000;
server.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}/`);
});
Run it:
node app.js
Open a browser and navigate to http://localhost:3000/ — you'll see Hello, Vizag! served over HTTP from your own machine.
Third-Party Modules
Third-party modules are installed via NPM. The most popular web framework for Node.js is express.
Installing Express:
npm install express
This adds express to your node_modules folder and records it as a dependency in package.json.
Building a Simple Express Server:
app.js:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello, Vizag!');
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}/`);
});
Run it:
node app.js
Navigating to http://localhost:3000/ displays Hello, Vizag! — this time powered by Express, with far less boilerplate than the raw http module.
Custom Modules
Custom modules let you split your code into separate files and reuse them across your application. You export a value using module.exports and load it with require().
Creating a Custom Module:
greet.js:
module.exports = function(name) {
return `Hello, ${name}!`;
};
Using the Custom Module:
app.js:
const greet = require('./greet');
const name = 'Vizag';
console.log(greet(name));
Run it:
node app.js
Output:
Hello, Vizag!
The ./greet path tells Node to look for greet.js in the same directory. No npm install needed — it's your own code.
Chapter 5: Asynchronous Programming with Node.js
Node.js handles multiple operations without blocking the main thread through asynchronous programming. the trainer walked the class through three progressively cleaner patterns for writing async code.
Callbacks
A callback is a function passed as an argument to another function, executed once an operation completes. It is the oldest async pattern in Node.js.
readFile.js:
const fs = require('fs');
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
console.log(data);
});
Run it:
node readFile.js
Output (assuming example.txt contains "Hello, Vizag!"):
Hello, Vizag!
Callbacks work, but deeply nested callbacks — "callback hell" — become difficult to read. Promises solve this.
Promises
Promises provide a cleaner way to handle asynchronous operations by chaining .then() and .catch() methods. The fs.promises API returns Promises instead of using callbacks.
readFilePromise.js:
const fs = require('fs').promises;
fs.readFile('example.txt', 'utf8')
.then((data) => {
console.log(data);
})
.catch((err) => {
console.error(err);
});
Run it:
node readFilePromise.js
The chain is flat and readable: do this, then do that, catch any error anywhere in the chain.
Async/Await
Async/await is syntactic sugar over Promises. It allows you to write asynchronous code that reads like synchronous code — no chains, no nested callbacks.
readFileAsync.js:
const fs = require('fs').promises;
async function readFile() {
try {
const data = await fs.readFile('example.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
}
readFile();
Run it:
node readFileAsync.js
The await keyword pauses execution inside the async function until the Promise resolves — but it never blocks the event loop. Other requests keep processing while this function waits. This is the modern standard for async Node.js code.
🧪 Try It Yourself
Task: Build a Node.js HTTP server that reads a text file and serves its contents.
- Create a file called
message.txtin your project folder and write any message inside it. - Create
server.jsusing this starter:
const http = require('http');
const fs = require('fs').promises;
const server = http.createServer(async (req, res) => {
try {
const content = await fs.readFile('message.txt', 'utf8');
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(content);
} catch (err) {
res.statusCode = 500;
res.end('Error reading file');
}
});
server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});
- Run it with
node server.js.
Success criterion: Opening http://localhost:3000/ in your browser displays the exact contents of message.txt. Try editing message.txt and refreshing — the server reads the file fresh on each request.
🔍 Checkpoint Quiz
Q1. Node.js is described as "single-threaded but highly concurrent." What makes this possible?
A) It spawns a new thread for each incoming request
B) It uses a non-blocking, event-driven architecture with an event loop
C) It delegates all I/O to the operating system kernel directly on the main thread
D) The V8 engine automatically parallelises JavaScript code
Q2. Given this code, what is printed to the console and when?
const fs = require('fs');
console.log('Start');
fs.readFile('data.txt', 'utf8', (err, data) => {
console.log('File read complete');
});
console.log('End');
A) Start → File read complete → End
B) Start → End → File read complete
C) File read complete → Start → End
D) It throws an error because readFile must be awaited
Q3. What is the bug in this custom module usage?
// math.js
module.exports = function add(a, b) {
return a + b;
};
// app.js
const add = require('math');
console.log(add(2, 3));
A) module.exports should be exports.add
B) The require path should be './math' not 'math' — without ./ Node looks in node_modules
C) You cannot export a function directly; it must be wrapped in an object
D) console.log cannot print the return value of a function
Q4. You have an async function that calls three external APIs in sequence, but each call does not depend on the previous result. How would you refactor it to be faster while still using async/await?
A1. B — Node's event loop allows the single thread to register I/O callbacks and move on immediately, achieving high concurrency without multiple threads.
A2. B — fs.readFile is non-blocking. Node registers the callback and continues executing synchronously, so Start and End print first. The callback fires once the file read completes.
A3. B — Bare module names like 'math' tell Node.js to look inside node_modules. Local files must be referenced with a relative path like './math'.
A4. Replace sequential await calls with Promise.all(): const [r1, r2, r3] = await Promise.all([fetchApi1(), fetchApi2(), fetchApi3()]);. This fires all three requests concurrently and waits for all to resolve, reducing total wait time from the sum of all three durations to the duration of the slowest one.
🪞 Recap
- Node.js is a V8-powered runtime that executes JavaScript on the server, outside the browser.
- Its single-threaded, non-blocking event loop makes it efficient for I/O-heavy applications without the overhead of multi-threading.
npm init -yscaffolds a project;node <file>runs it;npm install <package>adds dependencies.- Node.js modules come in three flavours: core (built-in), third-party (NPM), and custom (
require('./yourFile')). - Asynchronous code progresses from callbacks → Promises → async/await, with async/await being the modern preferred style.
📚 Further Reading
- Official Node.js Documentation — the source of truth for all core modules and APIs
- NPM Registry — browse and search over two million open-source packages
- Node.js Event Loop Explained — deep dive into how the event loop actually works
- Express.js Documentation — official docs for the Express web framework
- ⬅️ Previous: None
- ➡️ Next: The Model View Controller Pattern