Node.js Cluster IPC: Setup and Communication

Scaling Node.js applications often requires utilizing multiple CPU cores through clustering. This article provides a straightforward guide on how to set up a Node.js cluster using the native cluster module and facilitate seamless communication between the primary (master) process and worker processes using Inter-Process Communication (IPC).

Understanding Node.js Clustering and IPC

By default, Node.js runs in a single-threaded event loop. To leverage multi-core systems, the native cluster module allows you to spawn a network of worker processes that share the same server ports.

Because these processes run in separate operating system instances, they do not share memory. To allow them to coordinate, Node.js establishes an Inter-Process Communication (IPC) channel automatically when workers are forked. This channel permits the passing of messages back and forth using serialization.


Step-by-Step Implementation

Below is a complete, self-contained example demonstrating how to initialize a primary process, fork worker processes, and exchange data bidirectionally.

import cluster from 'node:cluster';
import { cpus } from 'node:os';
import process from 'node:process';

if (cluster.isPrimary) {
  console.log(`Primary process ${process.pid} is running.`);

  // Fork workers based on available CPU cores
  const numCPUs = cpus().length;
  for (let i = 0; i < numCPUs; i++) {
    const worker = cluster.fork();

    // 1. Listen for messages sent from this specific worker
    worker.on('message', (msg) => {
      console.log(`Primary received message from Worker ${worker.id}:`, msg);

      // 2. Reply back to the worker
      worker.send({ 
        reply: `Acknowledged message ${msg.id}`, 
        status: 'success' 
      });
    });
  }

  // Handle worker exits
  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} terminated. Code: ${code}, Signal: ${signal}`);
  });

} else {
  console.log(`Worker ${process.pid} started with ID: ${cluster.worker.id}`);

  // 3. Send an initial message to the primary process
  process.send({ 
    id: cluster.worker.id, 
    text: 'Hello from the worker process!' 
  });

  // 4. Listen for messages sent from the primary process
  process.on('message', (msg) => {
    console.log(`Worker ${cluster.worker.id} received message from Primary:`, msg);
  });
}

How the IPC Flow Works

The messaging pipeline relies on distinct methods depending on whether you are writing code for the primary process or the worker processes:

1. Sending Messages

2. Receiving Messages

3. Data Format

The payload passed through the send() method can be any serializable JavaScript object, array, string, number, or boolean. Node.js automatically stringifies the object to JSON internally and parses it upon arrival.