What Is Node.js?
Ryan Dahl created Node.js in 2009, embedding the V8 JavaScript engine in a C++ program that adds APIs for file system access, networking, processes, and more. Key characteristics:
- Single-threaded event loop β one thread handles all I/O via callbacks/Promises, avoiding thread management complexity.
- Non-blocking I/O β operations like reading files or querying databases don't block the thread; the loop continues processing while waiting for I/O.
- Same language everywhere β JavaScript on client and server reduces context switching and enables code sharing.
- npm ecosystem β over 2 million packages available.
Installing Node.js and Running Code
// Download from nodejs.org or use a version manager:
// nvm install 20 (Node Version Manager β recommended)
// nvm use 20
// Check versions
// $ node --version β v20.x.x
// $ npm --version β 10.x.x
// REPL (Read-Eval-Print Loop) β interactive shell
// $ node
// > 2 + 2
// 4
// > 'hello'.toUpperCase()
// 'HELLO'
// > .exit
// Run a file
// $ node app.js
// Basic Node.js script β hello.js
console.log('Hello from Node.js!');
console.log('Node version:', process.version);
console.log('Platform:', process.platform); // 'linux', 'darwin', 'win32'
console.log('Working dir:', process.cwd());
// process.argv β command-line arguments
// $ node greet.js Alice
const name = process.argv[2] || 'World';
console.log(`Hello, ${name}!`);
Hello from Node.js! Node version: v20.11.0 Platform: linux Working dir: /home/user/my-project
Node.js Global Objects
// __dirname β absolute path of current file's directory
console.log(__dirname); // /home/user/project/src
// __filename β absolute path of current file
console.log(__filename); // /home/user/project/src/app.js
// process β information about the running Node process
process.env.NODE_ENV = 'development'; // set env variable
console.log(process.env.PORT || 3000); // read env variable
process.exit(0); // exit with code 0 (success)
// Buffer β handle binary data
const buf = Buffer.from('Hello');
console.log(buf); // <Buffer 48 65 6c 6c 6f>
console.log(buf.toString()); // "Hello"
// global β equivalent of window in browsers (rarely used directly)
global.myConfig = { debug: true };
// setTimeout, setInterval, clearTimeout, clearInterval β same as browser
const timer = setTimeout(() => console.log('fired!'), 1000);
clearTimeout(timer);
Core Built-in Modules
// No npm install needed β built into Node.js
// fs β File System
const fs = require('fs');
// Or with ES modules: import fs from 'fs';
// Read file (async with callback)
fs.readFile('data.txt', 'utf8', (err, content) => {
if (err) throw err;
console.log(content);
});
// Read file (Promise-based β preferred)
const fsPromises = require('fs/promises');
const content = await fsPromises.readFile('data.txt', 'utf8');
console.log(content);
// Write file
await fsPromises.writeFile('output.txt', 'Hello Node!');
// path β cross-platform file path utilities
const path = require('path');
const filePath = path.join(__dirname, 'data', 'users.json');
console.log(path.basename(filePath)); // "users.json"
console.log(path.extname(filePath)); // ".json"
console.log(path.dirname(filePath)); // "/home/.../data"
// os β operating system info
const os = require('os');
console.log(os.platform()); // "linux"
console.log(os.cpus().length); // number of CPU cores
console.log(os.freemem()); // free memory in bytes
console.log(os.homedir()); // "/home/user"
npm Basics
// Initialize a project β creates package.json
// $ npm init -y
// Install a package (saved to dependencies)
// $ npm install express
// Install a dev dependency (only for development/build)
// $ npm install --save-dev nodemon
// Install globally (CLI tools)
// $ npm install -g typescript
// Remove a package
// $ npm uninstall lodash
// package.json structure
// {
// "name": "my-app",
// "version": "1.0.0",
// "main": "index.js",
// "scripts": {
// "start": "node index.js",
// "dev": "nodemon index.js",
// "test": "jest"
// },
// "dependencies": { "express": "^4.18.0" },
// "devDependencies": { "nodemon": "^3.0.0" }
// }
// Run scripts
// $ npm run dev
// $ npm start (shortcut β no "run" needed)
// $ npm test (shortcut β no "run" needed)
// npx β run a package without installing it globally
// $ npx create-react-app my-app
// $ npx nodemon index.js
Always add node_modules/ to your .gitignore. The package.json and package-lock.json files are sufficient for any developer to recreate the exact dependency tree by running npm install.
Built-in HTTP Server
const http = require('http');
const fs = require('fs/promises');
const path = require('path');
const server = http.createServer(async (req, res) => {
const url = req.url;
const method = req.method;
console.log(`${method} ${url}`);
if (url === '/' && method === 'GET') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>Hello from Node.js!</h1>');
} else if (url === '/api/users' && method === 'GET') {
const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(users));
} else {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Not Found' }));
}
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});
Express.js β The Standard Node Web Framework
Express adds routing, middleware, and a clean request/response API on top of Node's built-in http:
// npm install express
const express = require('express');
const app = express();
// Built-in middleware β parse JSON request bodies
app.use(express.json());
// Serve static files from /public folder
app.use(express.static('public'));
// Routes
app.get('/', (req, res) => {
res.send('<h1>Welcome to Express!</h1>');
});
app.get('/api/users', async (req, res) => {
try {
const users = await getUsersFromDB();
res.json(users);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// Route parameters
app.get('/api/users/:id', (req, res) => {
const { id } = req.params;
res.json({ id, name: 'Alice' });
});
// POST with body
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: 'name and email required' });
}
const newUser = { id: Date.now(), name, email };
res.status(201).json(newUser);
});
// Custom middleware β runs before route handlers
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next(); // pass to next middleware or route
});
app.listen(3000, () => console.log('Express server on port 3000'));
Browser JS vs Node.js
| Feature | Browser JavaScript | Node.js |
|---|---|---|
| Runtime environment | Browser tab | Server / CLI / scripts |
| Global object | window | global |
| DOM API | Yes (document, window) | No (no browser) |
| File system | No (sandboxed) | Yes (fs module) |
| Modules | ES Modules natively | CommonJS (require) or ESM |
| Package manager | CDN / importmap | npm / yarn / pnpm |
| HTTP | Fetch API (client) | Built-in http / Express (server) |
| Use cases | UI, interactivity | APIs, CLIs, build tools, scripts |
Node's single-threaded model excels at I/O-bound tasks (API calls, DB queries, file reads) but struggles with CPU-heavy work (image processing, video encoding, complex math). For CPU tasks, use Worker Threads, spawn a child process, or delegate to a language better suited to computation (Python, Rust, Go).
ποΈ Practical Exercise
Build a simple REST API with Express:
GET /api/notesβ return all notes (store in an in-memory array).GET /api/notes/:idβ return a single note by ID (404 if not found).POST /api/notesβ create a note from{ title, content }body; assign an auto-increment ID.DELETE /api/notes/:idβ remove a note; 204 on success, 404 if missing.- Test with curl or a browser extension like Thunder Client.
π₯ Challenge Exercise
Build a real-time chat server using Node.js built-in http and the ws npm package for WebSockets. The server: broadcasts messages from any client to all connected clients; prepends a random username to each message; stores the last 10 messages in memory and sends them to new connections. The client: a plain HTML page with a textarea and send button that connects via new WebSocket('ws://localhost:3000'). Open two browser tabs to test real-time updates.
Summary
π Summary
- Node.js runs JavaScript on the server using Chrome's V8 engine.
- Event-driven, non-blocking I/O makes Node efficient for API servers and real-time apps.
- Global objects:
process,__dirname,__filename,Buffer. - Core modules:
fs(file I/O),path(path utilities),http(server),os(system info). - npm manages packages;
package.jsondeclares dependencies and scripts. - Express.js adds routing, middleware, and a clean API on top of Node's
http. - Use
npxto run CLI tools without global installation.
Interview Questions
- What is the event loop in Node.js and how does non-blocking I/O work?
- What is the difference between
dependenciesanddevDependenciesin package.json? - What is middleware in Express? Give an example of a custom middleware.
- What is the difference between
npm installandnpx? - When is Node.js a poor choice for a task?
Frequently Asked Questions
CommonJS (require() / module.exports) is Node's original module system β synchronous, loaded at runtime. ES Modules (import / export) are the browser-standard, asynchronous module system added to Node in v12+. To use ESM in Node, add "type": "module" to package.json or use .mjs file extensions. Modern projects prefer ESM for consistency with browser code.
Node uses an event loop backed by libuv (a C library). When an I/O operation (database query, file read, HTTP request) is initiated, Node delegates it to the OS/thread pool and continues processing other events. When the I/O completes, a callback is placed in the event queue and the event loop picks it up on the next tick. This means Node can handle thousands of concurrent connections without spawning thousands of threads.
Express has the largest ecosystem and most tutorials β ideal for learning and legacy projects. Fastify is 2β4x faster and has schema-based validation built in. Hono is ultra-lightweight and edge-runtime compatible (Cloudflare Workers, Deno Deploy). For a new production API in 2026, Fastify or Hono are excellent choices; Express remains perfectly valid for most use cases.