Spawning Child Processes

node:child_process runs another program, in four ways. spawn streams, for long output and pipes; execFile buffers up to 1 MB, for short commands; exec buffers too but runs through a real shell, the only one of the four that does; fork streams and adds an IPC channel to a Node child.

execFile, spawn and fork side by sideJavaScript
import { execFile, spawn, fork } from 'node:child_process'; import util from 'node:util';
const run = util.promisify(execFile), node = process.execPath;
const { stdout } = await run(node, ['-p', 'process.versions.v8'], { timeout: 5000 });
console.log('execFile:', stdout.trim());
const child = spawn(node, ['-e', 'for (let i=1;i<=3;i++) console.log("tick",i)']);
child.stdout.setEncoding('utf8'); let seen = '';
for await (const chunk of child.stdout) seen += chunk;
await new Promise((r) => child.on('close', r));
console.log('spawn   :', JSON.stringify(seen), 'exit', child.exitCode);
const kid = fork(new URL('./child.js', import.meta.url), ['--role=worker']);
kid.send({ job: 'sum', values: [1, 2, 3, 4] });
kid.on('message', (m) => { console.log('fork    :', m); kid.disconnect(); });
Output
execFile: 14.1.146.11-node.20
spawn   : "tick 1\ntick 2\ntick 3\n" exit 0
fork    : { job: 'sum', total: 10, pid: 68016, argv: [ '--role=worker' ] }

child.js is three lines: process.on('message', ...) reads the job, process.send(...) replies. fork attaches that IPC channel; with spawn you would ask for it yourself, as stdio: ['pipe', 'pipe', 'pipe', 'ipc']. util.promisify(execFile) rejects on a non-zero exit, and the rejection carries code, stdout and stderr — where the useful message is.