iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

child_process

Node spawns OS processes via node:child_process: spawn for streaming, exec / execFile for buffered output, fork for child Node processes with IPC. Always prefer execFile over exec when you accept user input.

spawn, exec, execFile, fork

EXAMPLE
import { spawn, exec, execFile, fork } from 'node:child_process';
import { promisify } from 'node:util';
const execAsync = promisify(exec);
const execFileAsync = promisify(execFile);

// 1) spawn — streaming, no buffer limit
const proc = spawn('ffmpeg', ['-i', 'in.mp4', 'out.mkv']);
proc.stdout.on('data', (chunk) => process.stdout.write(chunk));
proc.stderr.on('data', (chunk) => process.stderr.write(chunk));
proc.on('close', (code) => console.log('exit', code));

// 2) execFile — SAFE — args are an array, no shell
const { stdout } = await execFileAsync('git', ['rev-parse', 'HEAD']);
console.log(stdout.trim());

// 3) exec — DANGEROUS with user input — string goes through a shell
await execAsync(`grep ${userInput} file.log`);   // injection vector!
// PREFER
await execFileAsync('grep', [userInput, 'file.log']);

// 4) Pipe processes
const grep = spawn('grep', ['ERROR']);
const tail = spawn('tail', ['-f', '/var/log/app.log']);
tail.stdout.pipe(grep.stdin);
grep.stdout.pipe(process.stdout);

// 5) fork — spawn another Node script with built-in IPC
const worker = fork('./worker.js');
worker.send({ task: 'process', payload: data });
worker.on('message', (result) => console.log('got', result));

// worker.js
process.on('message', async (msg) => {
    const result = await heavyWork(msg.payload);
    process.send({ task: msg.task, result });
});

// 6) AbortController — cancel a long-running child
const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 30_000);
await execFileAsync('long-task', [], { signal: ctrl.signal });

// 7) Environment + cwd + timeout
await execFileAsync('npm', ['ci'], {
    cwd:     '/tmp/build',
    env:     { ...process.env, CI: 'true' },
    timeout: 5 * 60 * 1000,
    maxBuffer: 16 * 1024 * 1024,
});

Why it matters

exec with user input is a Node-flavoured RCE. Default to execFile with an args array; the OS never sees a shell, special characters can’t do harm.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
import { execFile } from 'node:child_process';
execFile('git', ['status'], (err, stdout) => console.log(stdout));
Try it Yourself »

Discussion

Loading…