What is Node.js?
JavaScript began life as a language that could only run inside a web browser. If you wanted to write the server half of an application — the part that talks to a database and sends data back — you had to learn a second language such as PHP, Java or Python. Node.js removed that split. It is a runtime: a program that takes a JavaScript file and executes it directly on a machine, with no browser anywhere in sight.
The engine inside Node.js is V8, the same JavaScript engine that powers Google Chrome. V8 compiles JavaScript down to machine code rather than interpreting it line by line, which is why JavaScript today is far quicker than its old reputation suggests. Node.js wraps V8 in everything a browser deliberately withholds: the ability to open files, listen on a network port, read environment variables, and start other programs.
It is worth stating this plainly, because it is the single most common misunderstanding in a first interview. Node.js is not a language, and it is not a framework. The language is JavaScript, which you already know. The framework — if you use one — is something like Express, which you install separately. Node.js is the runtime underneath both of them.
The second thing that makes Node.js unusual is how it handles many users at once. A traditional setup gives each incoming request its own thread of execution; a thousand simultaneous users means a thousand threads, each holding memory and each sitting idle whenever the database is slow. Node.js instead runs your JavaScript on a single thread and refuses to sit and wait. When your code asks for a file or a database row, Node hands that job to the operating system, goes straight back to serving other requests, and comes back to your code when the answer arrives.
That design fits the work most web servers actually do, which is mostly waiting — waiting on a database, waiting on a payment gateway, waiting on some other company's API. It is a poor fit for work that keeps the processor busy, and that trade-off is the whole subject of the next two sections.
- A runtime, not a language — you still write plain JavaScript; Node.js is the program that runs it
- V8 engine — the same engine as Chrome, compiling JavaScript straight to machine code
- Event-driven — your code says what should happen when something finishes, instead of blocking until it does
- Non-blocking I/O — file, network and database work is handed to the operating system so the single thread stays free
- Full system access — files, network sockets, environment variables and child processes, none of which a browser page is allowed to touch
- npm — the package registry that ships with Node.js, and the largest public library ecosystem in programming
// Your first Node.js program
console.log('Hello from Node.js!');
// Node.js gives you access to system-level features
const os = require('os');
console.log('Platform:', os.platform());
console.log('CPU Cores:', os.cpus().length);
console.log('Free Memory:', Math.round(os.freemem() / 1024 / 1024), 'MB'); - Node.js is not a programming language — it is a runtime environment that lets you execute JavaScript outside the browser. When an interviewer asks "do you know Node?", they are asking whether you can build a server with JavaScript, not whether you have learned a second language.
One Thread, and Why That Matters on a Server
Your JavaScript in Node.js runs on exactly one thread. Every route handler, every loop, every JSON.parse takes its turn on that one thread. Node keeps a queue of pending work and a loop that picks the next item off it, runs it to completion, then picks the next. That loop is called the event loop, and understanding it is most of the difference between a Node developer and someone who copies Express snippets.
"Runs it to completion" is the phrase to hold on to. Once one of your functions starts, nothing else in your program can run until that function returns. In a script that only you run, this is harmless. On a server that many people share, it is the biggest way beginners accidentally take an application down.
Look at the example below. The /slow route spends several seconds inside a plain for loop doing arithmetic. Nothing about it is asynchronous, so there is no moment at which Node can slip away and do something else. If one user hits /slow, every other user who requests /fast during those seconds gets nothing at all — not a slow answer, no answer — until that loop finishes. A single request has frozen the entire server for everybody.
Now compare that with waiting on a database. When you await a query, your function pauses and the thread is released to serve other requests; when the database replies, your function resumes where it left off. Waiting is free. Computing is not. The rule that follows is short: in a request handler, never do heavy processor work on the main thread. Node's built-in worker_threads module exists for exactly that case, and pushing the job onto a background queue is the usual answer in a real application.
This is also why a bug in one route can look like "the whole site is down" rather than "one page is broken". In a threaded language the damage is usually contained to the request that caused it. In Node it is not, and that is worth remembering the first time an application mysteriously stops responding.
const express = require('express');
const app = express();
// BAD on a server: pure processor work on the only thread
app.get('/slow', (req, res) => {
let total = 0;
for (let i = 0; i < 3_000_000_000; i++) total += i; // blocks EVERYTHING
res.json({ total });
});
// This route is instant on its own...
app.get('/fast', (req, res) => {
res.json({ ok: true });
});
// ...but while /slow is running, /fast cannot answer at all.
// The single thread is busy, so every other request just waits in the queue.
// Waiting, by contrast, costs nothing:
app.get('/orders', async (req, res) => {
const orders = await db.findOrders(); // thread is FREE while this waits
res.json(orders);
});
app.listen(3000); - A picture that sticks: Node.js is one very fast waiter in a restaurant. He can take fifty orders in a few minutes, because taking an order is quick and the cooking happens in the kitchen. But the moment you ask him to chop onions for five minutes, every other table waits. Give him work that is mostly waiting, never work that is mostly chopping.
Where Node.js Fits, and Where It Does Not
Node.js is at its strongest wherever an application spends most of its life waiting for something outside itself. A REST API that reads and writes a database, a service that calls three other services and merges their answers, a chat server holding thousands of open connections — all of these are idle most of the time, and idleness is exactly what the event loop converts into throughput.
It is also the natural choice when the same small team writes both the frontend and the backend. One language, one package manager, and validation rules that can be shared between browser and server is a genuine saving on a college project or a startup of four people. Server-rendering frameworks such as Next.js and Nuxt are built on Node for the same reason.
The weak spot is processor-bound work: video transcoding, large image processing, training a model, generating a hundred-page PDF, brute-forcing anything. Node can do these, but while it does, its one thread is occupied and the rest of your users are stuck. The standard fixes are to move the job into a worker_threads worker, to hand it to a separate background process reading from a queue, or to call out to a service written in a language built for that kind of work.
Be honest about this trade-off in interviews instead of repeating that "Node is fast". Node is fast at handling many things at once. It is not fast at doing one very heavy thing. Knowing which of those two you are being asked about is what the question is really testing.
- Strong fit: REST and GraphQL APIs that mostly read and write a database
- Strong fit: real-time features — chat, live scoreboards, notifications, collaborative editing
- Strong fit: small services that mainly call other services and reshape the response
- Strong fit: command-line tools and build tooling, where npm distribution makes installation trivial
- Strong fit: server-side rendering with Next.js or Nuxt, sharing code with the frontend
- Weak fit: video and image processing, heavy number crunching, anything that pins the processor for seconds
- Weak fit: work that genuinely needs many processor cores in a single process without extra machinery
- If you must do heavy computation in a Node application, do not simply accept the freeze. Offload it —
worker_threadsfor something you need an answer to quickly, or a background job queue for something the user can be emailed about later.
How Node.js Differs From Browser JavaScript
The language is identical: same syntax, same array methods, same promises, same async/await. What changes is all the furniture around it, and a surprising share of beginner errors come from expecting the browser's furniture to still be there.
In the browser you have window, document, localStorage, alert and the whole DOM. None of these exist in Node.js, because there is no page and no user interface. Calling document.getElementById in a Node script throws ReferenceError: document is not defined, and that error nearly always means frontend code has been pasted into a backend file.
In return you get things a browser refuses to give any web page, and refuses for very good reasons: fs to read and write files on disk, http to listen on a network port, process to read environment variables and command-line arguments, and a module system for loading code from disk. The shared global object is called global rather than window, although modern code prefers globalThis, which is correct in both worlds.
There is one more difference that matters more than any API. In the browser, your code is downloaded onto a stranger's machine, so anyone can read it — nothing in it is secret. In Node.js, your code runs on a server you control. That is precisely why the database password and the payment gateway key belong here, and never in a React component.
// Works in Node.js, fails in the browser
const fs = require('node:fs/promises');
const data = await fs.readFile('users.json', 'utf8');
console.log(process.env.DATABASE_URL);
console.log(process.argv); // command-line arguments
// Works in the browser, fails in Node.js
// document.getElementById('app'); ReferenceError: document is not defined
// localStorage.setItem('k', 'v'); ReferenceError: localStorage is not defined
// alert('hi'); ReferenceError: alert is not defined
// Works in both
console.log('hello');
setTimeout(() => console.log('later'), 1000);
const res = await fetch('https://api.example.com/data');
console.log(globalThis === global); // true inside Node.js console.log,setTimeout,JSON,Promiseandfetchall behave the same in Node.js as in the browser, so most of your JavaScript knowledge transfers on day one. It is the environment that is new, not the language.
What This Course Builds Towards
This course is arranged so that each lesson is usable on its own but the whole sequence adds up to one thing: a working REST API that you could show in an interview or ship as the backend of a project. The first few lessons cover the runtime itself — installing it, splitting code into modules, reading files, and building a server with nothing but the built-in http module, so you can see what a framework is actually saving you from.
After that comes Express, which is the framework the rest of the course uses: routing, middleware, request bodies, and error handling. Then persistence — MongoDB through Mongoose and SQL through parameterised queries — followed by authentication with hashed passwords and tokens, configuration through environment variables, and the practices that separate a demo from something you would leave running.
Type the examples rather than copying them. Node error messages are unusually informative once you have seen a few, and the fastest way to see a few is to make the mistakes deliberately: forget an await, send two responses to one request, put a middleware in the wrong order. Every one of those has a lesson attached to it later in this course.
- Lessons 1–7: the runtime — modules, the file system, paths, the raw http module, npm
- Lessons 8–13: Express — routing, middleware, REST conventions, and a full CRUD API
- Lessons 14–15: databases — MongoDB with Mongoose, and SQL with parameterised queries
- Lessons 16–18: authentication, error handling, and configuration through environment variables
- Lessons 19–20: production practices, then a complete authenticated Task Manager API
- You need no prior backend experience for this course, but you should be comfortable with JavaScript objects, arrays, functions and promises. If
async/awaitstill feels shaky, revise it first — nearly every line of real Node.js code depends on it.
