Web Workers in Node.js: Parallel Execution Beyond Worker Threads

Mar 16, 2025


When we talk about multithreading in Node.js, we often mention Worker Threads (which we covered in this post). But did you know that Web Workers, a feature originally designed for browsers, can also be used in Node.js?

Today, we’ll dive into how Web Workers work in Node.js, when to use them, and how they compare to Worker Threads. πŸš€


πŸ”₯ What Are Web Workers?

Web Workers are separate JavaScript threads that run independently from the main execution thread. They are commonly used in browsers to prevent blocking the UI when running CPU-intensive tasks.

But as of Node.js 12, Web Workers are also supported in Node.js, allowing you to run JavaScript code in parallel just like Worker Threads!


βš™οΈ How Do Web Workers Work in Node.js?

In a browser, Web Workers are created using the Worker constructor with a separate JavaScript file. Node.js follows a similar pattern but with some key differences:

βœ… Runs scripts in separate threads.
βœ… Uses Message Passing (postMessage) for communication.
βœ… Can be used alongside Worker Threads.

However:
❌ Web Workers in Node.js do not share memory (unlike Worker Threads).
❌ You can’t use Node.js built-in modules inside Web Workers.


πŸ— Creating a Simple Web Worker in Node.js

Let's build a basic Web Worker that performs CPU-intensive calculations in the background.

Step 1: Create a Web Worker (worker.mjs)

// Web Worker script (worker.mjs)
onmessage = (event) => {
  const num = event.data;
  const result = fibonacci(num);
  postMessage(result);
};

function fibonacci(n) {
  return n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}

Step 2: Use the Web Worker in main.mjs

import { Worker } from "worker_threads"; // Using Worker from Worker Threads API

const worker = new Worker(new URL("./worker.mjs", import.meta.url));

worker.postMessage(40); // Send a task to the worker

worker.on("message", (result) => {
  console.log("βœ… Worker result:", result);
});

worker.on("error", (err) => {
  console.error("❌ Worker error:", err);
});

worker.on("exit", (code) => {
  console.log(`Worker exited with code ${code}`);
});

πŸ” What’s Happening?

  • worker.mjs calculates Fibonacci numbers when it receives a message.
  • The main thread sends 40 to the worker using postMessage().
  • The worker returns the result via postMessage().

This keeps the main thread responsive while offloading heavy computation to a background thread.


⚑ Web Workers vs. Worker Threads

Both Web Workers and Worker Threads allow parallel execution in Node.js, but they have key differences:

Web Workers vs. Worker Threads Comparison

Web Workers 🌐

  • Designed for: Browsers
  • Node.js Support: βœ… Yes (Node.js 12+)
  • Memory Sharing: ❌ No
  • Can use Node.js Modules: ❌ No
  • Communication: Message passing (postMessage)

Worker Threads πŸ› 

  • Designed for: Node.js
  • Node.js Support: βœ… Yes (Node.js 10+)
  • Memory Sharing: βœ… Yes (SharedArrayBuffer)
  • Can use Node.js Modules: βœ… Yes
  • Communication: Message passing + Shared Memory

When to Use What?

  • Use Web Workers β†’ If you're porting browser-based code to Node.js.
  • Use Worker Threads β†’ If you need shared memory & access to Node.js modules.
  • Use Both Together β†’ For a mix of frontend + backend parallelization.

🎯 Real-World Use Case: Offloading JSON Processing

Imagine your Node.js API receives large JSON payloads that need processing. Instead of blocking the event loop, let’s offload JSON parsing to a Web Worker.

Step 1: Create the Web Worker (json-worker.mjs)

onmessage = (event) => {
  const jsonData = event.data;
  const processedData = JSON.stringify(jsonData, null, 2); // Pretty-print JSON
  postMessage(processedData);
};

Step 2: Use the Web Worker in server.mjs

import express from "express";
import { Worker } from "worker_threads";

const app = express();
app.use(express.json());

app.post("/process-json", (req, res) => {
  const worker = new Worker(new URL("./json-worker.mjs", import.meta.url));

  worker.postMessage(req.body);

  worker.on("message", (processedJson) => res.send(processedJson));
  worker.on("error", (err) => res.status(500).send(err.message));
});

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

How This Helps

βœ… Main thread stays free – No blocking, even with large JSON.
βœ… Multiple requests handled efficiently – Each request gets its own worker.
βœ… Ideal for heavy computations – Parsing, data processing, etc.


πŸ”₯ Final Thoughts

Web Workers in Node.js provide a parallel execution model similar to Worker Threads, but with some key trade-offs.

  • βœ… Great for running browser-style parallel tasks.
  • ❌ Limited because they don’t support Node.js modules or shared memory.
  • βœ… Can be combined with Worker Threads for full multithreading power.

Want to push Node.js performance even further? Check out this post on Worker Threads for an even deeper dive! πŸš€

diogoaoliveira.com