Skip to main content

Command Palette

Search for a command to run...

Blocking & Non-Blocking Code in Node.js

Updated
•5 min read•View as Markdown
Blocking & Non-Blocking Code in Node.js
M
I write blogs to make concept easier for beginners.

JavaScript is a single-threaded language, meaning it executes code on one main thread. Node.js achieves asynchronous behavior not by making JavaScript multi-threaded, but by leveraging libuv which adds up the async behavior with event loop and thread pool .  

We’re going to understand Blocking & Non-Blocking code in Node.js.

Before going into the blog, Node.js is an open-source, cross-platform JavaScript runtime environment that allows developers to execute JavaScript code outside of a web browser, primarily for server-side and networking applications.  Node.js operates using an event-driven, non-blocking I/O model. It is not a programming language or a framework itself, but rather a runtime that provides the necessary environment and core libraries to run JavaScript on a server, operating system, or command line.

Now that we both have a base idea of what is Node.js, we can start exploring the blog below .

What Blocking Code Means

Blocking code means the program must wait for one task to finish before moving to the next task. Now it may sound good because that’s how it should be, but no honestly it depends  on our requirement. During this waiting time, nothing else can happen. 

Real-Life Analogy — One Cashier Shop

Imagine a shop with only one cashier. A customer comes with a huge order.

 While the cashier is handling that customer:

  • everyone else must wait

  • no new customer is served

  • the line becomes slow

That is exactly how blocking code works.

// Example

const fs = require("fs");
console.log("Start");
const data = fs.readFileSync("demo.txt", "utf8"); // reading file
console.log(data);
console.log("End");

// Output
Start
File Content Here
End

Here readFileSync blocks the execution. The server cannot continue until the task finishes.

Now let’s see Non-blocking code

What Non-Blocking Code Means

Non-blocking code means the program starts a task and immediately continues doing other work without waiting. When the task finishes, Node.js handles the result later.

Real-Life Analogy — Smart Waiter Imagine a waiter in a restaurant. The waiter:

  1. takes your order

  2. gives it to the kitchen

  3. immediately serves other tables The waiter does NOT stand near the kitchen waiting. When the food is ready, the kitchen notifies the waiter. That is how non-blocking Node.js works.

Example in Node.js

const fs = require("fs");
console.log("Start");
const data = fs.readFileAsync("demo.txt", "utf8");
console.log(data);
console.log("End");

// output 
Start 
End 
File Content Here

The application did NOT wait. This is non-blocking behavior

Difference Between Blocking and Non-Blocking Code

Blocking Code

Non-Blocking Code

Waits for the current task to finish before moving to the next task.

Code starts the task and moves to the next task without waiting.

The program execution stops until the operation is completed.

The program execution continues while the operation runs in the background.

Can make the application slow if a task takes too much time.

Code keeps the application fast and responsive.

Other users or requests must wait until the current task finishes.

Multiple users or requests can be handled at the same time.

It is mostly used with synchronous functions.

It is mostly used with asynchronous functions.

Blocking operations can freeze the Node.js event loop.

Non-blocking operations keep the event loop free.

Example: fs.readFileSync()

Example: fs.readFile()

Why Blocking Slows Server

This is where things become very important. Blocking code slows servers and to prevent this, Node.js uses a single main thread and an event loop, etc 

Imagine This Scenario

Suppose 100 users visit your website.

Each request needs to:

  • read a file

  • fetch data from database

  • call an API

With Blocking code like readfilesync

  • User 1 requests start

  • file reading starts

  • User 2 wait

  • User 3 waits …

  • so on...

One slow operation blocks everyone.

With Non-blocking code, like fs.readFile

  • User 1 requests starts

  • file reading in background

  • server handles User 2

  • then server handles User 3

  • so on..

 This makes Node.js highly scalable.

Async Operations in Node.js

Async operations means a task happens independently while the main program keeps running. These tasks keep on running behind the scenes and when finished, it then executes.

Node.js uses async operations for:

  • file handling

  • database queries

  • API calls

  • timers

  • network requests

Conclusion

Blocking and non-blocking code are very important concepts in Node.js. Blocking code waits for a task to finish before moving forward, while non-blocking code allows other tasks to continue running without waiting.

Because Node.js uses a single-threaded event loop, non-blocking operations help applications stay fast, responsive, and scalable. This is why most modern Node.js applications use asynchronous methods like callbacks, promises, and async/await.

Understanding these concepts will help you write better backend applications and improve server performance in real-world projects.