What Node.js is
Node.js (2009) took Chrome's JavaScript engine (V8) out of the browser and gave it server powers: files, sockets, processes. Result: the language of the frontend now runs backends — one language across the stack, one hiring pool, shared code.
But Node's real identity isn't "JS on servers." It's an execution model: a single thread plus an event loop, built for workloads that spend their time waiting.
The event loop — the concept this page exists for
A traditional server (classic Java, next page) dedicates a thread per request: request comes in, a thread walks it through, blocking — sitting idle — during every database call or API call. Threads are expensive (~1 MB stack each), so concurrency tops out around thousands.
Node runs one thread executing a loop:
Your code never waits. It starts the database query, hands over a callback ("run this when results arrive"), and returns to the loop — which immediately serves the next request. The waiting happens in the operating system, which is superb at watching thousands of sockets at once. When data arrives, the callback joins the queue.
Recall the speed gap: a database round trip is ~milliseconds, during which a CPU can do ~millions of operations. Thread-per-request wastes that time sleeping; the event loop spends it serving other requests. That's why one Node process handles tens of thousands of concurrent connections — and why Node was the natural first home for WebSocket-heavy apps.
Modern syntax hides callbacks behind async/await, but the model is
unchanged — await means "park me, loop, carry on; resume me when
ready":
app.get("/orders/:id", async (req, res) => {
const order = await db.orders.findById(req.params.id); // parked, not blocking
res.json(order);
});
The one rule: never block the loop
One thread means any CPU-heavy synchronous work freezes every request in the process. A 200 ms image resize = 200 ms where nobody gets a response:
app.get("/report", (req, res) => {
const stats = crunchTenMillionRows(); // ❌ synchronous CPU work:
res.json(stats); // the whole server is frozen
});
Fixes: push CPU work to a worker thread or a separate service behind a
queue; use the async version of every API
(never fs.readFileSync in a handler). The interview phrasing: Node is
superb for I/O-bound workloads, wrong for CPU-bound ones — know which
your endpoint is.
One core busy ≠ machine busy: production runs one Node process per CPU core (cluster mode / PM2 / containers, Level 10) behind a load balancer.
Express — the minimal framework
Express is Node's classic web framework: tiny, unopinionated, and the vocabulary every other framework borrows.
import express from "express";
const app = express();
app.use(express.json()); // middleware: parse JSON bodies
const requireAuth = (req, res, next) => { // middleware: runs BEFORE handlers
const user = verifyToken(req.headers.authorization);
if (!user) return res.status(401).json({ error: "unauthenticated" });
req.user = user; // enrich the request
next(); // pass to the next layer
};
app.get("/api/orders", requireAuth, async (req, res) => {
const orders = await db.orders.forUser(req.user.id);
res.json(orders); // 200 + JSON
});
app.post("/api/orders", requireAuth, async (req, res, next) => {
try {
const order = await createOrder(req.user, req.body); // validate inside!
res.status(201).json(order);
} catch (err) {
next(err); // forward to the error middleware
}
});
app.use((err, req, res, next) => { // error middleware: catch high
console.error(err); // log once (with a real logger)
res.status(500).json({ error: "internal error" });
});
app.listen(3000);
The load-bearing idea is middleware: a pipeline of functions each
seeing (req, res, next) — parsing, logging, auth, rate limiting, then
your handler, then error handling. It's the
Chain of Responsibility pattern as a framework,
and the same shape appears in Spring's filters and FastAPI's dependencies.
Notice also throw low, catch high — handlers
throw, one error middleware translates to a clean
500.
Production perspective
- Who runs Node: Netflix's API layer, PayPal, LinkedIn's mobile backend, Uber's dispatch edges — overwhelmingly the I/O-bound, fan-out-to-services tier. This very site's tooling (Next.js dev server, bundlers) is Node.
- The ecosystem is the superpower and the liability: npm is the
largest package registry on earth;
left-padand supply-chain attacks are the cautionary tales. Lock your dependencies (security). - TypeScript is the default in serious codebases — the static-typing seatbelt retrofitted; you'll meet it properly in Level 8.
- Express alternatives you'll hear: Fastify (faster Express), NestJS (Spring-flavored structure for Node). Concepts transfer one-to-one.
Common mistakes
- Blocking calls in handlers —
readFileSync, heavy JSON parsing, crypto loops, unboundedforover millions of rows. The whole process stalls. - Forgetting
await—const user = db.findUser(id)(no await) gives you a Promise object, not a user; the bug surfaces two lines later asuser.name === undefined. - Unhandled promise rejections — an async error nobody caught crashes the process (modern Node). Error middleware + a process-level handler.
- Trusting
req.body— it's user input (never trust the client); validate with a schema library (zod/joi) before it touches logic. - One process on an 8-core box — 7 cores idle; cluster it.
Interview perspective
Practice
- Build: the Express API above, plus
GET /api/orders/:idreturning 404 when missing. Test withcurl; watch status codes (Level 0's families). - See the loop: add
app.get("/block", ...)that runs a 2-second synchronous loop, and/fastthat returns instantly. Hit/blockthen/fastin parallel — observe/faststall. Now move the work to a worker thread and watch it not. - Middleware reps: write a logging middleware (method, path, duration) and a naive per-IP rate limiter (a dict of counters) — then read rate limiting for the real algorithms.
- Connect: read the StockVision deep-dive and identify which of its endpoints are I/O-bound vs CPU-bound, and what that implies for runtime choice.
Next: Java Spring Boot — the opposite philosophy: maximum structure, thread-per-request, and the enterprise standard.