🟢 Node.js Q42 / 118

What is the difference between spawn and fork?

AI-Powered Answer ✓ Answered

In Node.js, both `child_process.spawn()` and `child_process.fork()` are functions used to create new processes that run independently of the main Node.js process. While they both achieve process creation, they are designed for different use cases and have distinct underlying mechanisms.

Core Concepts

child_process.spawn(): This function is used to launch a new process with a given command and a list of arguments. It's the most fundamental child process function in Node.js. It streams data from the child process back to the parent. spawn is ideal for running external system commands like ls, grep, or even non-Node.js programs, and for operations that involve large amounts of data being streamed in or out.

child_process.fork(): This function is a special case of spawn(). It's specifically designed to spawn new Node.js processes. The key difference is that fork() establishes an Inter-Process Communication (IPC) channel between the parent and child processes. This channel allows messages to be passed back and forth, making it perfect for creating worker processes that perform tasks and report results back to the main application. Each forked process runs a separate V8 instance, ensuring isolation.

Key Differences Summarized

Feature`child_process.spawn()``child_process.fork()`
PurposeRun any external command/programRun new Node.js processes
IPC ChannelNo built-in IPC (can be simulated with stdio)Built-in IPC channel for message passing
CommunicationStandard I/O streams (stdin, stdout, stderr)Message-passing via `send()` and `on('message')`
V8 InstanceNot applicable (for non-Node.js programs); uses same V8 as parent if Node.jsAlways a new, separate V8 instance
Use CasesExecuting shell commands, running non-Node.js scripts, streaming dataCreating worker processes, parallelizing CPU-bound tasks, managing long-running operations

Example: Using `spawn`

This example demonstrates spawning a simple ls -lh command to list files in the /usr directory.

javascript
const { spawn } = require('child_process');

const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

Example: Using `fork`

This example shows a parent process forking a child Node.js script and exchanging messages. Assume child.js contains a simple message handler.

javascript
// parent.js
const { fork } = require('child_process');
const path = require('path');

const child = fork(path.join(__dirname, 'child.js'));

child.on('message', (message) => {
  console.log('Message from child:', message);
});

child.send({ hello: 'child' }); // Send message to child

child.on('exit', (code) => {
  console.log(`Child process exited with code ${code}`);
});

// --- child.js (conceptual content for the child script) ---
// process.on('message', (message) => {
//   console.log('Message from parent:', message);
//   process.send({ hello: 'parent', result: 42 }); // Send message back
// });
// process.exit(0);

For child.js to work with the parent, it would typically listen for message events on the global process object and use process.send() to reply.