Skip to main content

Command Palette

Search for a command to run...

Blocking vs Non-Blocking Code in Node.js

Published
β€’4 min read

When building backend systems, one of the most important concepts to understand is how your server handles tasks. In Node.js, this comes down to blocking vs non-blocking code β€” a core reason why Node.js is fast and scalable.

Let’s break it down in a simple, practical way.


🚧 What is Blocking Code?

Blocking code means: πŸ‘‰ The program waits for a task to finish before moving to the next line.

Example (Synchronous / Blocking)

const fs = require("fs");

const data = fs.readFileSync("file.txt", "utf-8");
console.log(data);

console.log("Next line");

What happens here:

  1. Node starts reading the file

  2. It pauses everything else

  3. Only after reading completes β†’ it prints "Next line"

❗ Problem

If the file is large or slow to access:

  • The entire server is stuck

  • No other user request can be processed


⚑ What is Non-Blocking Code?

Non-blocking code means: πŸ‘‰ The program does not wait β€” it moves forward and handles the result later.

Example (Asynchronous / Non-Blocking)

const fs = require("fs");

fs.readFile("file.txt", "utf-8", (err, data) => {
  console.log(data);
});

console.log("Next line");

What happens here:

  1. File read starts in background

  2. Node immediately moves on

  3. "Next line" prints first

  4. File result prints later


🧠 Simple Analogy

Think of it like ordering food:

Blocking

  • You go to a restaurant

  • Stand at the counter until your food is ready

  • Do nothing else

Non-Blocking

  • You order food

  • Sit with friends / do other work

  • Get notified when food is ready

πŸ‘‰ Node.js works like the second scenario.


🐒 Why Blocking Code Slows Down Servers

Node.js uses a single-threaded event loop.

That means:

  • Only one main thread handles all requests

  • If one request blocks β†’ everything else waits

Real Impact:

If 100 users hit your server:

  • Blocking β†’ requests handled one-by-one ❌

  • Non-blocking β†’ requests handled concurrently βœ…


πŸ”„ Async Operations in Node.js

Node.js is designed around asynchronous (async) operations, such as:

  • File system operations (fs)

  • Database queries

  • API calls

  • Network requests

These tasks are:

  • Delegated to background workers

  • Returned via callbacks, promises, or async/await


πŸ“‚ Real-World Example: File Handling

Blocking Version

app.get("/", (req, res) => {
  const data = fs.readFileSync("largeFile.txt", "utf-8");
  res.send(data);
});

πŸ”΄ Problem:

  • Each request waits for file read

  • Server becomes slow under load


Non-Blocking Version

app.get("/", (req, res) => {
  fs.readFile("largeFile.txt", "utf-8", (err, data) => {
    res.send(data);
  });
});

🟒 Advantage:

  • Server continues handling other requests

  • Much better performance


πŸ—„οΈ Real-World Example: Database Calls

Blocking (Bad Practice)

const user = db.getUserSync(id);

Non-Blocking (Correct)

db.getUser(id).then(user => {
  console.log(user);
});

or

const user = await db.getUser(id);

πŸ‘‰ Database operations are slow β€” always keep them async.


βš–οΈ Blocking vs Non-Blocking Summary

Feature Blocking Code ❌ Non-Blocking Code βœ…
Execution Waits Continues immediately
Performance Slow Fast
Scalability Poor High
Use Case Rare (startup scripts) Almost everywhere in Node

🎯 When (If Ever) to Use Blocking?

Blocking code is acceptable when:

  • Running startup scripts

  • CLI tools

  • One-time operations (not handling users)

πŸ‘‰ Never use blocking code in production servers.


πŸš€ Final Takeaway

  • Node.js shines because of non-blocking architecture

  • Blocking code defeats its purpose

  • Always prefer:

    • Callbacks

    • Promises

    • async/await

πŸ‘‰ If your server feels slow, chances are you're accidentally blocking the event loop.