DEV Community

Cover image for πŸš€ Worker Threads in Node.js: A Complete Guide for Parallel Processing
ROHIT SINGH
ROHIT SINGH

Posted on

πŸš€ Worker Threads in Node.js: A Complete Guide for Parallel Processing

πŸ”Ή Introduction

Node.js is widely loved for its non-blocking I/O model. This makes it perfect for building scalable applications like APIs, chat apps, or real-time dashboards.

But here’s the catch πŸ‘‰ Node.js is single-threaded by default.

That means if your app needs to perform CPU-intensive tasks like:

πŸ”„ Image processing

πŸ“Š Data analysis

πŸ” Password hashing

πŸ€– Machine learning

…the event loop will get blocked β›”, and your app becomes slow or even unresponsive.

So, how do we fix this? πŸ€”

The answer is: Worker Threads.

πŸ”Ή What are Worker Threads in Node.js?

Worker Threads are a built-in multithreading feature introduced in Node.js v10.5.0 (and stable from v12+).

They allow us to:

Run JavaScript in parallel threads.

Offload heavy computations.

Keep the main event loop free to handle API requests and other async operations.

πŸ‘‰ Think of Worker Threads as dedicated helpers that run in the background while your main thread handles users.

πŸ”Ή Worker Threads vs Child Processes

Many developers confuse Worker Threads with Child Processes. Let’s clear this up πŸ‘‡

Feature Worker Threads Child Processes
Memory Shared memory via SharedArrayBuffer Separate memory
Communication Fast, via postMessage Slower (via IPC)
Use case CPU-bound tasks Isolated tasks (like separate microservices)

πŸ‘‰ If you need parallel computation, use Worker Threads.
πŸ‘‰ If you need separate execution environments, use Child Processes.

πŸ”Ή Example 1: Basic Worker Thread
worker.js (Worker file)

const { parentPort } = require("worker_threads");

parentPort.on("message", (num) => {
  let result = 0;
  for (let i = 0; i < num; i++) {
    result += i;
  }
  parentPort.postMessage(result);
});

main.js (Main thread)
const { Worker } = require("worker_threads");

function runWorker(num) {
  return new Promise((resolve, reject) => {
    const worker = new Worker("./worker.js");

    worker.postMessage(num);

    worker.on("message", resolve);
    worker.on("error", reject);
    worker.on("exit", (code) => {
      if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`));
    });
  });
}

(async () => {
  console.log("Main thread free for requests...");
  const result = await runWorker(1000000);
  console.log("Worker Result:", result);
})();

Enter fullscreen mode Exit fullscreen mode

βœ… The worker thread calculates the sum.
βœ… The main thread remains free to handle HTTP requests.

πŸ”Ή Example 2: Image Processing with Worker Threads

Imagine your Node.js API allows users to upload profile pictures. If you resize images in the main thread, the API will hang. Instead, use a worker πŸ‘‡

// imageWorker.js
const sharp = require("sharp");
const { parentPort } = require("worker_threads");

parentPort.on("message", async (filePath) => {
  try {
    await sharp(filePath)
      .resize(200, 200)
      .toFile("resized-" + filePath);
    parentPort.postMessage("Image resized successfully!");
  } catch (err) {
    parentPort.postMessage("Error: " + err.message);
  }
});

// server.js
const express = require("express");
const multer = require("multer");
const { Worker } = require("worker_threads");

const app = express();
const upload = multer({ dest: "uploads/" });

app.post("/upload", upload.single("image"), (req, res) => {
  const worker = new Worker("./imageWorker.js");
  worker.postMessage(req.file.path);

  worker.on("message", (msg) => {
    res.send(msg);
  });
});

app.listen(3000, () => console.log("Server running on port 3000"));


Enter fullscreen mode Exit fullscreen mode

πŸ”₯ Now your API can process images without blocking users.

πŸ”Ή Advantages of Worker Threads

βœ”οΈ Utilizes multi-core CPUs effectively.
βœ”οΈ Prevents event loop blocking.
βœ”οΈ Easy message-based communication.
βœ”οΈ Ideal for CPU-heavy tasks.

πŸ”Ή Disadvantages

❌ Higher memory usage compared to async functions.
❌ Too many workers = performance overhead.
❌ Not needed for I/O-bound tasks (use async/await instead).

πŸ”Ή Best Practices

βœ… Use Worker Threads for CPU-bound tasks only.
βœ… Implement a worker pool (using libraries like Piscina) for multiple workers.
βœ… Use SharedArrayBuffer if threads need to share memory.
βœ… Monitor worker performance with logging.

πŸ”Ή FAQs

Q1: Can Worker Threads access Node.js modules?
πŸ‘‰ Yes, they can use any Node.js module.

Q2: Are Worker Threads faster than async/await?
πŸ‘‰ Only for CPU-bound tasks. For I/O (like DB queries, API calls), async/await is better.

Q3: How many Worker Threads should I create?
πŸ‘‰ Ideally, equal to the number of CPU cores.

πŸ”Ή Conclusion

Worker Threads in Node.js are a powerful tool for improving performance when handling CPU-intensive tasks.

They:

βœ… Keep your app responsive.

βœ… Utilize multi-core processors.

βœ… Allow parallel execution.

If you’re building high-performance applications like AI APIs, image processors, or big-data crunchers, Worker Threads are your best friend.

πŸš€ Rohit Singh πŸš€ – Medium

Read writing from πŸš€ Rohit Singh πŸš€ on Medium. Full-stack developer with 6+ years in Angular, Node.js & AWS. Sharing tips, best practices & real-world lessons from building scalable apps.

favicon medium.com

Top comments (0)