Mastering Processes and Threads in Node.js: From Basics to Multi‑Process Architecture

This comprehensive guide explains the fundamentals of processes and threads, demonstrates practical Node.js demos for single‑threaded and multi‑threaded scenarios, and walks through creating child processes, multi‑process architectures, and daemon services, providing clear code examples and performance insights for backend developers.

Node Underground
Node Underground
Node Underground
Mastering Processes and Threads in Node.js: From Basics to Multi‑Process Architecture

Quick Navigation

Process

Thread

Node.js Thread and Process

Node.js Process Creation

Node.js Multi‑process Architecture Model

Daemon Process

Process

Process is the basic unit of resource allocation in an operating system and serves as a container for threads. A simple Node.js process can be started with node app.js. The example shows how to set process.title, read process.pid, and use a demo file process.js to display the PID.

const http = require('http');
http.createServer(() => {
  process.title = 'Test Process Node.js';
  console.log(`process.pid: ${process.pid}`);
}).listen(3000);

Thread

Thread is the smallest unit of CPU scheduling and belongs to a process. JavaScript runs in a single‑threaded event loop, while languages like Java support true multithreading. The article provides a blocking computation example that illustrates why asynchronous code is essential in Node.js.

// compute.js
const http = require('http');
http.createServer((req, res) => {
  if (req.url === '/compute') {
    // heavy computation
  } else {
    res.end('ok');
  }
}).listen(3000);

Single Thread

JavaScript executes code sequentially; long‑running synchronous operations block the event loop. Using asynchronous APIs prevents this blockage.

Multi Thread

Java multithreading example demonstrates a shared variable count that is modified by multiple threads, showing how each thread has its own stack but shares the process memory.

public class TestApplication {
    static Integer count = 0;
    // ...
}

Node.js Thread and Process

Node.js runs on the V8 engine, employing an event‑driven, non‑blocking I/O model. It can operate in a single‑process single‑thread mode or a multi‑process single‑thread mode using child_process.fork (Cluster) to leverage multiple CPU cores.

Process Object

process.env – environment variables

process.nextTick – next‑tick queue

process.pid – current process ID

process.ppid – parent process ID

process.cwd() – current working directory

process.platform – OS platform

process.uptime() – process uptime

process.on('uncaughtException') – catch uncaught errors

process.stdout, process.stdin, process.stderr – standard streams

Node.js Process Creation

spawn

const { spawn } = require('child_process');
const child = spawn('ls', ['-l'], { cwd: '/usr' });
child.stdout.pipe(process.stdout);

exec

const { exec } = require('child_process');
exec('node -v', (error, stdout, stderr) => {
  console.log({ error, stdout, stderr });
});

execFile

const { execFile } = require('child_process');
execFile('node', ['-v'], (error, stdout, stderr) => {
  console.log({ error, stdout, stderr });
});

fork

const { fork } = require('child_process');
const compute = fork('./fork_compute.js');
compute.send('start computation');
compute.on('message', sum => {
  // handle result
});

Using fork for CPU‑intensive Tasks

A parent server delegates heavy computation to a child process via process.send and receives the result with a message event.

// fork_app.js (parent)
const { fork } = require('child_process');
const compute = fork('./fork_compute.js');
compute.send('start');
compute.on('message', sum => {
  res.end(`Sum is ${sum}`);
  compute.kill();
});

Node.js Multi‑process Architecture Model

The master process creates a TCP server, forks worker processes equal to the number of CPU cores, distributes incoming connections, restarts workers on exit, and handles graceful shutdown signals.

// master.js
const { fork } = require('child_process');
const cpus = require('os').cpus().length;
const server = require('net').createServer();
server.listen(3000);
function createWorker() {
  const worker = fork('worker.js');
  worker.on('message', msg => {
    if (msg.act === 'suicide') createWorker();
  });
  worker.on('exit', (code, signal) => {
    delete workers[worker.pid];
    // optional restart logic
  });
  worker.send('server', server);
  workers[worker.pid] = worker;
}
for (let i = 0; i < cpus; i++) createWorker();
process.once('SIGINT', close.bind(this,'SIGINT'));

Worker code creates its own HTTP server, receives the shared server handle from the master, and demonstrates error handling with process.on('uncaughtException').

// worker.js
process.title = 'node-worker';
process.on('message', (msg, handle) => {
  if (msg === 'server') {
    const server = handle;
    server.on('connection', socket => {
      // handle connection
    });
  }
});
process.on('uncaughtException', err => {
  process.send({ act: 'suicide' });
  process.exit(1);
});

Daemon Process

A daemon runs in the background after its parent exits. The example creates a detached child process with detached: true, sets its working directory, ignores stdio, and calls unref() so the parent can terminate.

// index.js
const { spawn } = require('child_process');
function startDaemon() {
  const daemon = spawn('node', ['daemon.js'], {
    cwd: '/usr',
    detached: true,
    stdio: 'ignore'
  });
  console.log(`Daemon started parent pid: ${process.pid}, daemon pid: ${daemon.pid}`);
  daemon.unref();
}
startDaemon();

The daemon script logs its PID and PPID every 10 seconds to log files, keeping the process alive.

// daemon.js
const fs = require('fs');
const { Console } = require('console');
const logger = new Console(
  fs.createWriteStream('./stdout.log'),
  fs.createWriteStream('./stderr.log')
);
setInterval(() => {
  logger.log('daemon pid:', process.pid, 'ppid:', process.ppid);
}, 10000);

Running node index.js starts the daemon, which can be observed in the system activity monitor as a separate background process.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendNode.jsmulti-processdaemonprocessesThreads
Node Underground
Written by

Node Underground

No language is immortal—Node.js isn’t either—but thoughtful reflection is priceless. This underground community for Node.js enthusiasts was started by Taobao’s Front‑End Team (FED) to share our original insights and viewpoints from working with Node.js. Follow us. BTW, we’re hiring.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.