What is Node.js?
Node.js is a runtime environment. It lets you run JavaScript code outside of a browser. Before Node.js, JavaScript only worked inside web browsers. Now, you can use JavaScript to build servers, tools, and full applications.
Ryan Dahl created Node.js in 2009. He built it on Google's V8 JavaScript engine. The V8 engine compiles JavaScript into fast machine code. This makes Node.js very fast and efficient.
Where is Node.js Used?
Many large companies use Node.js in production. Here are some major examples:
| Company | What they use Node.js for | Scale |
|---|---|---|
| Netflix | Streaming backend, fast startup time | 300M+ users |
| Mobile backend, replaced Ruby on Rails | 10x fewer servers needed | |
| Uber | Real-time trip dispatch system | Millions of requests/second |
| NASA | EVA spacewalk data system | Critical real-time data |
Node.js vs Traditional Server Approaches
- Creates a new thread for each request
- Waits (blocks) while reading files or database
- Uses more memory per connection
- Harder to scale under heavy load
- Uses a single thread for all requests
- Continues while waiting — never blocks
- Very low memory usage per connection
- Scales easily to handle millions of requests
How Node.js Works
Node.js has three key components that work together. Understanding these three parts will help you write better Node.js code.
The Event Loop — Step by Step
Here is what happens when a request arrives in Node.js:
Synchronous vs Asynchronous Code
This is the most important concept in Node.js. Here is the difference:
// ❌ SYNCHRONOUS — Blocks everything (avoid this) const fs = require('fs'); const data = fs.readFileSync('file.txt'); // WAITS here console.log(data); // Only runs after file is read console.log('This waits too...'); // Everything is blocked // ✅ ASYNCHRONOUS — Never blocks (use this) fs.readFile('file.txt', 'utf8', (err, data) => { if (err) throw err; console.log(data); // Runs when file is ready }); console.log('This runs immediately!'); // Does not wait
Promises and Async/Await (Modern Approach)
Modern Node.js uses async/await. It makes asynchronous code look like synchronous code. It is cleaner and easier to read.
const fs = require('fs').promises; // Using async/await — clean and readable async function readMyFile() { try { const data = await fs.readFile('file.txt', 'utf8'); console.log(data); } catch (err) { console.log('Error:', err.message); } } readMyFile();
Node.js runs on a single thread, but it never sits idle. The Event Loop keeps it busy. While one task waits for data, Node.js processes other requests. This is why it handles millions of connections with low memory.
Build a Web Application
Let's build a complete web application with Node.js. We will use only built-in modules — no third-party libraries. The app will serve web pages and handle API requests.
my-app/ → server.js, data.json, public/ (index.html, app.js, style.css)
Step 1 — Install Node.js
Go to nodejs.org and download the LTS version. LTS stands for Long Term Support. It is the most stable version. After installing, check if it works:
# Check Node.js version node --version # Should print: v20.x.x or higher npm --version # Should print: 10.x.x or higher # Create your project folder mkdir my-app cd my-app
Step 2 — Create the Server
This server does three things. It serves static files. It handles API routes. It sends proper HTTP responses.
const http = require('http'); const fs = require('fs'); const path = require('path'); const url = require('url'); // In-memory data store (replaces a database) let tasks = [ { id: 1, title: 'Learn Node.js', done: false }, { id: 2, title: 'Build a server', done: false } ]; // Map file extensions to MIME types const mimeTypes = { '.html': 'text/html', '.css': 'text/css', '.js': 'text/javascript', '.json': 'application/json' }; // Helper: send a JSON response function sendJSON(res, status, data) { res.writeHead(status, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); } // Helper: serve static files from /public function serveStatic(req, res) { let filePath = path.join(__dirname, 'public', req.url === '/' ? 'index.html' : req.url); fs.readFile(filePath, (err, data) => { if (err) { res.writeHead(404); res.end('Not Found'); return; } const ext = path.extname(filePath); res.writeHead(200, { 'Content-Type': mimeTypes[ext] || 'text/plain' }); res.end(data); }); } // Main request handler const server = http.createServer((req, res) => { const parsed = url.parse(req.url, true); const pathname = parsed.pathname; // API Routes if (pathname === '/api/tasks' && req.method === 'GET') { return sendJSON(res, 200, { success: true, tasks }); } if (pathname === '/api/tasks' && req.method === 'POST') { let body = ''; req.on('data', chunk => body += chunk); req.on('end', () => { const { title } = JSON.parse(body); const newTask = { id: Date.now(), title, done: false }; tasks.push(newTask); sendJSON(res, 201, { success: true, task: newTask }); }); return; } // Serve static files for everything else serveStatic(req, res); }); server.listen(3000, () => { console.log('✅ Server running → http://localhost:3000'); });
Step 3 — Create the Frontend
The frontend talks to our server using fetch(). It displays tasks and lets users add new ones. No framework is needed.
// Load tasks when the page opens async function loadTasks() { const res = await fetch('/api/tasks'); const json = await res.json(); const list = document.getElementById('task-list'); list.innerHTML = json.tasks .map(t => `<li>${t.title}</li>`) .join(''); } // Add a new task async function addTask(title) { await fetch('/api/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title }) }); loadTasks(); // Refresh the list } document.getElementById('add-btn') .addEventListener('click', () => { const input = document.getElementById('task-input'); if (input.value.trim()) { addTask(input.value.trim()); input.value = ''; } }); loadTasks(); // Run on page load
Step 4 — Run Your Application
node server.js # Output: ✅ Server running → http://localhost:3000 # Open your browser and go to http://localhost:3000
You built a working web server in pure Node.js. It serves HTML pages, handles GET and POST requests, stores data in memory, and parses JSON — all without any libraries.
Built-in Modules You Used
| Module | Purpose | Key Methods |
|---|---|---|
| http | Create HTTP servers and clients | createServer, listen |
| fs | Read and write files on disk | readFile, writeFile, readFileSync |
| path | Work with file and folder paths | join, extname, basename |
| url | Parse URLs and query strings | parse, format |
| crypto | Generate hashes, tokens, UUIDs | createHash, randomUUID |
Node.js Cheat Sheet
Keep these patterns handy. They cover 90% of what you need in real Node.js applications.
const http = require('http'); const server = http.createServer((req, res) => { res.writeHead(200, {'Content-Type': 'text/html'}); res.end('<h1>Hello World</h1>'); }); server.listen(3000);
const fs = require('fs').promises; // Read const data = await fs.readFile('file.txt', 'utf8'); // Write await fs.writeFile('out.txt', 'Hello!');
function getBody(req) { return new Promise((resolve) => { let body = ''; req.on('data', chunk => body += chunk); req.on('end', () => resolve(JSON.parse(body))); }); } const data = await getBody(req);
const url = require('url'); // req.url = '/search?q=nodejs&page=2' const parsed = url.parse(req.url, true); parsed.pathname; // '/search' parsed.query.q; // 'nodejs' parsed.query.page; // '2'
const crypto = require('crypto'); function hashPassword(password) { return crypto .createHash('sha256') .update(password) .digest('hex'); }
const routes = { 'GET /': handleHome, 'GET /api/users': getUsers, 'POST /api/users': createUser, }; const key = `${req.method} ${req.url}`; const handler = routes[key]; handler ? handler(req, res) : send404(res);
const fs = require('fs').promises; // Read JSON file as object const raw = await fs.readFile('data.json', 'utf8'); const data = JSON.parse(raw); // Save object as JSON file await fs.writeFile('data.json', JSON.stringify(data, null, 2));
function setCORS(res) { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); }