Topic 1 of 18 · Node Expert

Topic 1 : Introduction and Foundation

Lesson TL;DRTopic 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 but...
7 min read·beginner·node-js · javascript · npm · modules

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

  1. 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.
  2. 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.
  3. Fast Execution — Built on the V8 JavaScript engine, Node.js compiles JavaScript directly to native machine code, executing it quickly.
  4. 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:

ModulePurpose
fsFile system operations (read, write, delete files)
httpCreate web servers and handle HTTP requests
pathWork 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.

  1. Create a file called message.txt in your project folder and write any message inside it.
  2. Create server.js using 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/');
});
  1. 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) StartFile read completeEnd
B) StartEndFile read complete
C) File read completeStartEnd
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 -y scaffolds 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

Like this topic? It’s one of 18 in Node Expert.

Block your seat for ₹2,500 and join the next cohort.