Node.js Architecture
What is Node.js Architecture?
Node.js uses a single-threaded, event-driven architecture that is designed to handle many connections at once, efficiently and without blocking the main thread.
This makes Node.js ideal for building scalable network applications, real-time apps, and APIs.
Key Characteristics: Non-blocking I/O, event-driven, single-threaded with event loop, asynchronous execution
Node.js Architecture Diagram
Here is a simple overview of how Node.js processes requests:
1. Client Request Phase
- Clients send requests to the Node.js server
- Each request is added to the Event Queue
2. Event Loop Phase
- The Event Loop continuously checks the Event Queue
- Picks up requests one by one in a loop
3. Request Processing
- Simple (non-blocking) tasks are handled immediately by the main thread
- Complex/blocking tasks are offloaded to the Thread Pool
4. Response Phase
- When blocking tasks complete, their callbacks are placed in the Callback Queue
- Event Loop processes callbacks and sends responses
Non-blocking Examples
Example: Non-blocking File Read
const fs = require('fs');
console.log('Before file read');
fs.readFile('myfile.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log('File contents:', data);
});
console.log('After file read');
Run example »
Notice how "After file read" is printed before the file contents, showing that Node.js does not wait for the file operation to finish.
Example: Blocking vs Non-blocking Code
// Blocking code example
console.log('Start of blocking code');
const data = fs.readFileSync('myfile.txt', 'utf8'); // Blocks here
console.log('Blocking operation completed');
// Non-blocking code example
console.log('Start of non-blocking code');
fs.readFile('myfile.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log('Non-blocking operation completed');
});
console.log('This runs before the file is read');
Run example »
Key Difference: The first example blocks the entire process until the file is read, while the second example allows other operations to continue while the file is being read.
When to Use Node.js
Node.js is particularly well-suited for:
- I/O-bound applications - File operations, database queries, network requests
- Real-time applications - Chat apps, live notifications, collaboration tools
- APIs - RESTful services, GraphQL APIs
- Microservices - Small, independent services
Note: Node.js may not be the best choice for CPU-intensive tasks as they can block the event loop. For such cases, consider:
- Using worker threads
- Creating a microservice in a more suitable language
- Using native add-ons
Summary
Node.js is fast and efficient because it uses a non-blocking event loop and delegates heavy work to the system.
This allows it to handle thousands of connections at the same time, with minimal resources.
Key Benefits:
- Handles many concurrent connections efficiently
- Great for I/O-bound applications
- Uses JavaScript on both client and server
- Large ecosystem of packages (npm)