# Blocking vs Non-Blocking Code in Node.js

When working with Node.js, one of the most important concepts to understand is the difference between blocking and non-blocking code. This directly affects how fast and scalable your application will be.

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

* * *

## 1\. What Blocking Code Means

Blocking code is when a task stops the execution of the program until it is finished.

In simple terms:

*   The system waits
    
*   Nothing else can run during that time
    

### Example:

```js
const fs = require('fs');

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

console.log('This runs after file is read');
```

### What happens:

*   File is read completely first
    
*   Only then the next line runs
    

This blocks the main thread.

* * *

## 2\. What Non-Blocking Code Means

Non-blocking code allows the program to continue executing while a task is running in the background.

Instead of waiting:

*   The task is started
    
*   The program moves forward
    
*   Result is handled later
    

### Example:

```js
const fs = require('fs');

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

console.log('This runs before file is read');
```

### What happens:

*   File reading starts
    
*   Program continues immediately
    
*   Result is printed later
    

* * *

## 3\. Why Blocking Slows Servers

In Node.js, everything runs on a **single thread**.

If one request uses blocking code:

*   It stops the thread
    
*   Other requests must wait
    

### Example scenario:

*   User A → file read (blocking)
    
*   User B → simple request
    

User B will have to wait until User A’s task is finished.

This leads to:

*   Slow response times
    
*   Poor scalability
    
*   Bad user experience
    

* * *

## 4\. Async Operations in Node.js

Node.js is designed to use asynchronous (async) operations.

Instead of blocking:

*   Tasks are handled in the background
    
*   Callbacks, Promises, or async/await are used
    

### Example with async/await:

```js
const fs = require('fs/promises');

async function readFile() {
  const data = await fs.readFile('file.txt', 'utf-8');
  console.log(data);
}

readFile();
console.log('This runs first');
```

Even though `await` looks like it pauses execution, Node.js is still handling it efficiently without blocking other operations.

* * *

## 5\. Real-World Examples

* * *

### a) File Reading

**Blocking:**

```js
fs.readFileSync('data.txt');
```

**Non-blocking:**

```js
fs.readFile('data.txt', callback);
```

* * *

### b) Database Calls

**Blocking (bad practice):**

*   Waiting for database response before doing anything else
    

**Non-blocking (correct approach):**

```js
db.query('SELECT * FROM users', (err, result) => {
  console.log(result);
});
```

Or using async/await:

```js
const users = await db.query('SELECT * FROM users');
```

* * *

### c) API Calls

**Non-blocking example:**

```js
fetch('/api/data')
  .then(res => res.json())
  .then(data => console.log(data));

console.log('Runs immediately');
```

* * *

## Final Understanding

*   Blocking code stops execution until a task finishes
    
*   Non-blocking code allows other tasks to run in parallel
    
*   Blocking operations slow down Node.js servers
    
*   Node.js is built around asynchronous, non-blocking behaviour
    
*   Real-world applications rely heavily on non-blocking code
    

* * *

## Summary

Understanding blocking vs non-blocking code is essential for writing efficient Node.js applications. Since Node.js uses a single-threaded model, blocking operations can freeze the entire server and delay all incoming requests. Non-blocking code solves this by allowing tasks to run in the background while the system continues processing other requests. By using asynchronous patterns like callbacks, promises, and async/await, you can build fast, responsive, and scalable applications that handle multiple users efficiently.
