Node.js Cheatsheet
Child Processes
Use this Node.js reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Four APIs at a Glance
| API | Returns | Use When |
|---|---|---|
exec(cmd, cb) | ChildProcess | Shell command, small output, one-liner |
execFile(file, args, cb) | ChildProcess | Known binary, no shell, small output |
spawn(cmd, args) | ChildProcess | Stream large output, long-running process |
fork(module, args) | ChildProcess | Spawn another Node.js module with IPC |
execSync / spawnSync | Buffer/object | Scripts, build steps where blocking is OK |
exec — Shell Command
import { exec } from "node:child_process"; import { promisify } from "node:util"; const execAsync = promisify(exec); // Callback style exec("ls -la /tmp", (err, stdout, stderr) => { if (err) { console.error("Exit code:", err.code); console.error(stderr); return; } console.log(stdout); }); // Promise style (recommended) const { stdout, stderr } = await execAsync("git log --oneline -5"); console.log(stdout); // With options const { stdout } = await execAsync("npm pack --dry-run", { cwd: "/path/to/project", env: { ...process.env, NODE_ENV: "production" }, timeout: 30_000, // ms — kill after this maxBuffer: 10 * 1024 * 1024, // 10 MB stdout/stderr buffer shell: "/bin/bash", encoding: "utf8", });
Shell injection risk: never pass untrusted user input to
exec. UseexecFileorspawninstead.
execFile — Binary Without Shell
import { execFile } from "node:child_process"; import { promisify } from "node:util"; const execFileAsync = promisify(execFile); const { stdout } = await execFileAsync("ffprobe", [ "-v", "quiet", "-print_format", "json", "-show_format", "video.mp4", ]); const meta = JSON.parse(stdout);
spawn — Streaming Output
import { spawn } from "node:child_process"; const child = spawn("find", ["/usr", "-name", "*.js"], { cwd: "/", env: process.env, stdio: "pipe", // "pipe" | "inherit" | "ignore" | Stream }); // Stream stdout child.stdout.setEncoding("utf8"); child.stdout.on("data", (chunk) => process.stdout.write(chunk)); child.stderr.on("data", (chunk) => process.stderr.write(chunk)); child.on("close", (code, signal) => console.log("exited", code, signal)); child.on("error", (err) => console.error("spawn error", err)); child.on("spawn", () => console.log("process started")); // Send data to child's stdin child.stdin.write("hello\n"); child.stdin.end(); // Kill child.kill("SIGTERM"); child.kill(); // SIGTERM default
stdio Options
// "pipe" — create pipe between parent and child (default) // "inherit" — share parent's stdio (child output goes to terminal) // "ignore" — discard (redirect to /dev/null) // Stream — use that stream directly spawn("node", ["server.js"], { stdio: "inherit" }); // output to terminal spawn("cmd", ["arg"], { stdio: "ignore" }); // discard all spawn("cmd", ["arg"], { stdio: [process.stdin, process.stdout, "ignore"], // mixed }); // Create IPC channel alongside stdio spawn("node", ["worker.js"], { stdio: ["pipe", "pipe", "pipe", "ipc"] });
fork — IPC with Another Node.js Module
// parent.js import { fork } from "node:child_process"; const child = fork("./worker.js", ["--mode=fast"], { execArgv: ["--max-old-space-size=512"], // node flags for child env: { ...process.env, WORKER: "1" }, silent: false, // true = pipe child's stdio instead of inheriting }); // Send message to child (IPC — JSON-serializable) child.send({ type: "start", data: [1, 2, 3] }); // Receive message from child child.on("message", (msg) => { console.log("from child:", msg); }); child.on("exit", (code) => console.log("worker exited", code)); // worker.js process.on("message", (msg) => { if (msg.type === "start") { const result = heavyWork(msg.data); process.send({ type: "result", result }); } });
Synchronous Variants
import { execSync, execFileSync, spawnSync } from "node:child_process"; // execSync — returns Buffer or string; throws on non-zero exit const out = execSync("git rev-parse HEAD", { encoding: "utf8" }).trim(); // Silence output execSync("npm install", { stdio: "ignore" }); // spawnSync — returns result object const result = spawnSync("node", ["--version"], { encoding: "utf8" }); result.stdout; // string result.stderr; // string result.status; // exit code (null if killed by signal) result.signal; // signal name or null result.error; // Error object if spawn failed result.pid; // child PID
ChildProcess Properties and Events
child.pid; // child process ID child.exitCode; // null while running, number after exit child.signalCode; // signal that killed it, or null child.killed; // true after kill() called child.connected; // IPC channel open? child.channel; // IPC channel object (fork only) // Events child.on("spawn", () => { ... }); // process started child.on("error", (err) => { ... }); // failed to start child.on("exit", (code, signal) => { ... }); // fires first, stdio may not be flushed child.on("close", (code, signal) => { ... }); // after stdio closed — use this child.on("message", (msg, handle) => { ... }); // IPC (fork) child.on("disconnect", () => { ... }); // IPC channel closed // Disconnect IPC (fork) child.disconnect(); process.disconnect(); // inside worker
Passing Handles (Advanced IPC)
// Send a server handle to a worker (load balancing) import net from "node:net"; import { fork } from "node:child_process"; const worker = fork("./worker.js"); const server = net.createServer(); server.listen(3000, () => { worker.send("server", server); // transfer handle server.close(); }); // worker.js process.on("message", (msg, handle) => { if (msg === "server") { handle.on("connection", (socket) => { socket.end("handled by worker\n"); }); } });
Common Patterns
// Run a shell command and get trimmed output async function run(cmd) { const { stdout } = await execAsync(cmd); return stdout.trim(); } const branch = await run("git branch --show-current"); // Stream a long-running process with live output function runLive(cmd, args, opts = {}) { return new Promise((resolve, reject) => { const child = spawn(cmd, args, { stdio: "inherit", ...opts }); child.on("close", (code) => { if (code === 0) resolve(); else reject(Object.assign(new Error(`Exit ${code}`), { code })); }); child.on("error", reject); }); } await runLive("npm", ["run", "build"]); // Kill a child process after a timeout const child = spawn("long-task", []); const timer = setTimeout(() => child.kill("SIGKILL"), 60_000); child.on("close", () => clearTimeout(timer)); // Detached process (survives parent exit) const daemon = spawn("node", ["daemon.js"], { detached: true, stdio: "ignore", }); daemon.unref(); // allow parent to exit without waiting for child