Spawn Other Programs From Node
child_process
Run shell commands or other programs from Node. spawn, exec, fork — three flavors.
What you'll learn
- Use spawn for streaming output
- Use exec for short commands
- Use fork for spawning Node sub-processes
Sometimes Node needs to run another program — invoke git,
shell out to ffmpeg, or fork a sub-process. That’s
node:child_process.
exec — Short Commands
Returns the entire stdout/stderr at once:
import { exec } from "node:child_process";
import { promisify } from "node:util";
const run = promisify(exec);
const { stdout } = await run("git rev-parse HEAD");
console.log("commit:", stdout.trim()); Use for: one-off commands with small output.
Don’t use with untrusted input — exec runs through a shell.
spawn — Streaming
For long-running processes or big output:
import { spawn } from "node:child_process";
const ls = spawn("ls", ["-la", "."]);
ls.stdout.on("data", (chunk) => process.stdout.write(chunk));
ls.stderr.on("data", (chunk) => process.stderr.write(chunk));
ls.on("close", (code) => {
console.log(`exited with ${code}`);
}); stdout/stderr are streams. Memory stays low even for huge output. Arguments are passed as an array — no shell injection risk.
execFile — Like exec, Safer
Same as exec but bypasses the shell. Pass args as an array:
import { execFile } from "node:child_process";
import { promisify } from "node:util";
const run = promisify(execFile);
const { stdout } = await run("git", ["log", "--oneline", "-5"]); Prefer this over exec when you can.
fork — Node Sub-process
A specialized spawn for Node scripts, with IPC:
// main.mjs
import { fork } from "node:child_process";
const child = fork("./worker.mjs");
child.send({ task: "do thing" });
child.on("message", (msg) => console.log("child says", msg)); // worker.mjs
process.on("message", (msg) => {
process.send({ result: 42 });
}); Use when you want process-level isolation that worker_threads doesn’t provide (separate V8 heap, separate event loop).
Choosing
| Tool | Use for |
|---|---|
exec | Quick shell commands, small output |
execFile | Same, but safer (no shell) |
spawn | Big or streaming output |
fork | Spawn another Node script with IPC |