From Browser to Backend: Why Node.js Is a Game-Changer

Mahadev KeshariMahadev Keshari
14 min read

Table of contents

JavaScript on the Server: Enter Node.js

When we think of JavaScript, we usually think of it running inside a web browser—managing button clicks, animations, and interacting with web pages. But did you know you can also run JavaScript on the server?

Thanks to Node.js, JavaScript is no longer limited to the front-end. It’s now a powerful tool for building full-stack applications.

What Is Server-Side JavaScript?

Server-side JavaScript refers to using JavaScript to write code that runs outside the browser, typically on a server. This code handles things like:

  • Serving web pages

  • Responding to API requests

  • Connecting to databases

  • Managing files and user data

But wait—browsers can’t run JavaScript outside their sandbox. So how do we do this?

Meet Node.js

Node.js is an open-source, cross-platform JavaScript runtime environment that allows you to run JavaScript code outside of a web browser. It is built on top of Google Chrome’s V8 JavaScript engine.

In simple terms:

Normally, JavaScript runs in the browser (like Chrome or Firefox). But with Node.js, you can run JavaScript on your computer/server like any other programming language (Python, C++, etc.).

Here’s what makes Node.js awesome:

  • Non-blocking I/O: Handles multiple operations at once, perfect for real-time and high-performance apps.

  • Huge ecosystem: The Node Package Manager (npm) gives access to thousands of libraries.

  • Single language for frontend and backend: Use JavaScript everywhere!

  • Asynchronous and Non-blocking: Great for building fast, scalable network applications (like APIs, chat apps).

  • Event-driven: Handles many connections efficiently.

  • NPM (Node Package Manager): Comes with a huge ecosystem of libraries (over 1 million packages).

  • Used for Backend Development: Often paired with Express.js to build REST APIs, websites, etc


Why Use JavaScript on the Server?

Using JavaScript on the server means:

  • You can build scalable and fast applications

  • Use the same language across your entire tech stack (frontend + backend)

  • Easily handle real-time data (like in chat apps, live updates, etc.)

It’s especially useful for I/O-heavy applications, like REST APIs or applications that deal with lots of file, network, or database operations.

This is simple code for running JavaScript on your server after installing necessary dependencies:-

// server.mjs 
import { createServer } from 'node:http';

const server = createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello World!\n');
});

// starts a simple http server locally on port 3000
server.listen(3000, '127.0.0.1', () => {
  console.log('Listening on 127.0.0.1:3000');
});

// run with `node server.mjs`

Comparison about Node.js and PHP


FeatureNode.jsPHP
SpeedVery fast – handles many tasks at once (non-blocking, asynchronous)Slower – runs one task at a time (blocking, synchronous)
FlexibilityHighly flexible – thousands of packages via npmFlexible – fewer tools, but still useful
Development CostLower cost – small teams can build big appsCan be higher – large projects may need more experts
TestingGood tools for testing (like Jest, Mocha) with better error handlingBasic testing – slower and harder for complex code
Request HandlingHandles many users at once (non-blocking I/O)One request at a time – can slow down with heavy traffic
Real-time SupportGreat for real-time apps (chat, live updates)Not ideal – needs extra tools for real-time features
Learning CurveModerate – need to learn JavaScript, callbacks, promises, async/awaitEasy – beginner-friendly syntax
Community SupportLarge and active – backed by Google and open-source communityHuge – around for many years, lots of resources and forums
Best Use CasesAPIs, dashboards, chat apps, SPAs, real-time systemsBlogs, CMS like WordPress, small to medium websites
Database SupportWorks best with NoSQL (like MongoDB), but supports SQL tooWorks best with MySQL/MariaDB, traditional SQL databases

Let’s know the fact behind the Node.js:-


Node.js is built on several key technologies. Here's a breakdown of what Node.js is made up of : -


1. V8 JavaScript Engine (by Google)

  • This is the brain that runs JavaScript code.

  • It's the same engine used in Google Chrome.

  • Node.js uses it to run JavaScript outside the browser (like on your computer/server).

  • It's written in C++ and is super fast because it compiles JavaScript into machine code (code your computer understands directly).


2. libuv

  • A powerful C library that helps Node.js handle things like:

    • Reading files

    • Talking to databases

    • Working with the network (e.g. servers, HTTP)

  • It gives Node.js its famous non-blocking, asynchronous behavior using something called the event loop.

The event loop lets Node handle many things at once without waiting for one to finish before starting another.

Multithreading in Node.js with Libuv

Even though JavaScript runs on a single thread, Node.js is multithreaded under the hood, thanks to libuv.


Summary Table:

FeatureThreaded?Handled By
JavaScript codeSingle-threadedV8 Engine
File system I/OMultithreadedlibuv Thread Pool
DNS, crypto, compressionMultithreadedlibuv Thread Pool
HTTP, TCP socketsNon-blockingOS-level + libuv
worker_threads moduleMultithreadedSeparate JS threads

1. Libuv Thread Pool

  • Default: 4 threads (can be changed via UV_THREADPOOL_SIZE)

  • Used for non-network blocking tasks:

    • fs.readFile()

    • crypto.pbkdf2()

    • zlib compression

    • dns.lookup()

These tasks are offloaded to the libuv thread pool, so your main JS thread doesn't block.

jsCopyEditconst fs = require('fs');

fs.readFile('bigfile.txt', () => {
  console.log('File read done'); // Done by a libuv thread
});

2. Worker Threads Module (Since Node.js v10.5.0+)

  • Allows true multithreading for JavaScript code.

  • Each Worker runs in its own V8 instance + event loop.

  • Great for CPU-intensive tasks like image processing, math, ML, etc.

jsCopyEditconst { Worker } = require('worker_threads');

new Worker(`
  const { parentPort } = require('worker_threads');
  parentPort.postMessage('Hello from Worker!');
`, { eval: true });

Think of this like Web Workers in the browser, but in Node.js.


3. When to Use Threads in Node.js

Use CaseApproach
File I/Olibuv handles this
CPU-bound workworker_threads
Parallel tasks (compute)worker_threads
Offloading blocking opslibuv thread pool
Sharing data across threadsSharedArrayBuffer

4. How to Check Multithreading in Action

Use top, htop, or Task Manager to observe multiple threads during:

  • crypto.pbkdf2()

  • fs.readFile() on large files

  • Spawning multiple Worker threads


Advanced Tip: Increase Thread Pool Size

bashCopyEditUV_THREADPOOL_SIZE=8 node yourscript.js

Use this if you’re running multiple file/crypto tasks in parallel.

Node.js as a Chef in a Restaurant

The Main Chef = JavaScript Thread

Imagine Node.js is a single chef in a busy restaurant kitchen. This chef (JavaScript engine) handles:

  • Taking orders

  • Plating food

  • Talking to customers

But the chef doesn’t cook everything alone...


Libuv = Kitchen Staff / Assistants

Behind the scenes, the chef has a team of assistants (libuv thread pool) who help with:

  • Boiling pasta (File I/O)

  • Chopping veggies (Crypto)

  • Washing dishes (DNS)

The chef just says:
"Hey, assistant! Boil pasta while I serve this customer!"

Then continues working without waiting.

That’s asynchronous I/O.


Event Loop = Order Bell

When an assistant finishes a task, they ring the bell.

The chef (event loop) hears the bell and says:
"Okay! Time to serve that pasta."

This is how callbacks are executed — the event loop checks who’s done and runs their code.


Worker Threads = Extra Chefs

Sometimes, tasks are too CPU-heavy — like making sushi from scratch 🍣.

So the main chef hires another chef (worker thread) who works independently in another kitchen (thread), with their own order bell and knives.

They don’t share a cutting board (memory) unless they use SharedArrayBuffer.


Final Mapping:

Restaurant ConceptNode.js Feature
Main ChefJS Main Thread (V8)
Kitchen Assistantslibuv Thread Pool
Ringing BellEvent Loop Callback
Extra Chefworker_threads
Order QueueCallback/Event Queue

Final Thought

Node.js gives you event-driven, non-blocking I/O by default, but multithreading is available when needed via:

  • libuv (for built-in async I/O)

  • worker_threads (for custom threading)


3. Core Modules (Built-in Libraries)

  • These are the tools Node.js gives you out of the box, like:

    • http – for making servers

    • fs – for working with the file system

    • path, crypto, and more

  • Some are written in JavaScript, others in C++ (when they need to do low-level stuff).


4. Bindings (Bridge between JS and C++)

  • Node.js is built with both JavaScript and C++.

  • Bindings act like a translator, letting JavaScript talk to C++ code.

Example: When JavaScript says fs.readFile(), behind the scenes it uses C++ code to actually access your files.


5. npm (Node Package Manager)

  • Comes installed with Node.js.

  • Lets you download and use third-party packages (pre-made tools/modules) like:

    • express – to build web servers

    • mongoose – to work with MongoDB

    • lodash, axios, and thousands more!

Think of it like a Play Store for JavaScript packages mongoose, etc.)

What is the Event Loop in Node.js?

The event loop is the heart of Node.js that helps it handle many tasks at once without waiting.


Imagine this:

You are a waiter in a restaurant:

  • Instead of waiting for one table’s food to be ready before taking the next order...

  • You take orders from many tables.

  • As soon as one dish is ready, you serve it, then move on.

That's how the event loop works — it doesn’t block, it keeps moving.


Why is it Important?

  • Node.js runs on a single thread (only one task at a time).

  • But thanks to the event loop, it can handle many requests at the same time.

  • It's perfect for web servers, chat apps, and real-time applications.


How it works (in simple steps):

  1. Incoming task (like reading a file or handling a web request) comes in.

  2. If it's quick, it runs right away.

  3. If it's slow (like waiting for a file or database), Node puts it aside and continues with other tasks.

  4. Once the slow task is ready, Node puts it back in the queue.

  5. The event loop picks it up and runs it.


Real-world Benefits:

  • Fast and efficient

  • Handles many users at the same time

  • Great for apps that don’t wait on one user

    Input and Output (I/O) Operations in Node.js


    🔹 What is I/O?

    • Input (I): Any data you give to the program.
      Example: Typing something, clicking a button, reading from a file.

    • Output (O): Any data the program gives you back.
      Example: Printing text, showing a result, writing to a file.


Types of I/O in Node.js:

TypeMeaningExample
Synchronous I/OBlocks other operations until it finishesReading a file and waiting for result
Asynchronous I/ODoesn’t block – Node.js keeps working while waiting for resultReading a file, then using a callback later

Why Asynchronous I/O is Better in Node.js:

  • Node.js is single-threaded (one task at a time).

  • So it uses non-blocking I/O to handle many users at once.

  • It helps with performance, especially in web apps and APIs.


Common I/O Operations in Node.js:

OperationExample ModuleUse
Read a filefs moduleGetting data from a file
Write to a filefs moduleSaving something to a file
Read user inputreadline moduleTaking input from terminal
Send data to clienthttp moduleSending output as a response in a server

Node.js I/O Analogy – Pizza Delivery Shop Style


The Scenario:

You're running a pizza shop with one chef (just like Node.js has one thread).


Synchronous I/O (Blocking):

  • A customer orders a pizza .

  • The chef makes the pizza and doesn’t do anything else until it's ready.

  • Only after the pizza is served can the chef take the next order.

Slow service. Customers have to wait.


Asynchronous I/O (Non-Blocking – like Node.js):

  • A customer orders a pizza.

  • The chef sends the order to the oven, then takes the next order immediately.

  • When the oven beeps , the chef serves the ready pizza.

  • Multiple pizzas can cook while the chef keeps working.

Fast service. Many customers are served at once.


How It Relates to Node.js:

Pizza Shop PartNode.js Equivalent
ChefNode.js (single-threaded)
Pizza OrdersIncoming I/O requests (like file reads, APIs)
Oven TimerCallback/Event loop
Ready PizzaOutput (like server response, file content)

Key Point:

Just like a smart chef doesn’t wait around, Node.js keeps working while waiting for input/output to complete.

What is Non-Blocking?

  • Normally, when you ask a computer to do something (like read a file), it waits until the task is done.
    This is blocking.

  • In non-blocking, the computer doesn’t wait — it starts the task and moves on to the next one.
    When the task is finished, the computer comes back to it.


What is Event-Driven?

  • The computer waits for certain events to happen (like a user clicking a button, or a file being read).

  • When an event happens, the computer reacts to it by running a function (called a callback).

  • It's like saying: "Let me know when you're done, and I’ll handle it."


So, What is Node.js’s Model?

  • Node.js is non-blocking → It doesn’t stop for slow tasks.

  • Node.js is event-driven → It listens and reacts to events.

This makes Node.js fast and efficient, even though it runs on a single thread (only one main worker).

Movie Ticket Counter Analogy


Blocking (Old Way)

  • You go to buy a movie ticket.

  • The person at the counter helps only one person at a time.

  • They wait until the payment is done before helping the next person.

Others have to wait in line even for small tasks.


Non-Blocking + Event-Driven (Node.js Way)

  • You go to buy a ticket.

  • The person takes your name, then says:

    “I’ll call you when your ticket is ready.”

  • Meanwhile, they help the next person.

  • As soon as your ticket is ready, they call your name and give it to you.

No waiting. Everyone is helped quickly.
They only act when something is ready (event-driven).


In short:

  • Non-blocking = Don’t wait for one task to finish.

  • Event-driven = Respond when something is done.

Traditional vs Event-Driven Request Handling


Traditional Request Handling (Blocking Model)

  • Every request is handled one at a time using a separate thread.

  • The system waits for a task to finish (like reading from a database) before doing the next one.

  • Like:
    "Stand in line, wait your turn."

Easy to understand

Slower and less scalable when many users connect


Event-Driven Request Handling (Non-Blocking Model)

  • All requests are handled on a single thread.

  • When a task takes time, Node.js moves on and comes back to it later (when it’s done).

  • Like:
    "Place your order, and we’ll call your name when it’s ready."

Fast, efficient, scalable

Needs more planning and structure


Real-World Analogy: Restaurant

StepTraditional (Blocking)Event-Driven (Non-Blocking)
Taking ordersWaiter handles one customer at a timeWaiter takes all orders quickly
CookingWaiter waits in kitchen until food is readyKitchen cooks in background
Serving foodOnly after cooking, next order is takenFood is served when ready
Customer experienceSlow in busy hoursFast and smooth

Summary Table

FeatureTraditional ModelEvent-Driven Model (Node.js)
Thread per requestYes (multi-threaded)No (single-threaded)
BlockingYesNo (non-blocking)
PerformanceSlower with many usersFast and scalable
Code styleSimplerNeeds callbacks/events
Best use caseSmall websitesReal-time apps, APIs, chat systems
10
Subscribe to my newsletter

Read articles from Mahadev Keshari directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mahadev Keshari
Mahadev Keshari