Child processes
A child process is another program that yours starts: git, an archiver, an image converter or another Node.js script. The node:child_process module lets you start it, pass arguments and get the result. This is useful when an existing utility already does what you need.
execFile: getting the result
execFile() starts a program, waits for it to finish and returns all its output. Combined with promisify() from node:util it can be awaited:
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const run = promisify(execFile);
const { stdout } = await run(process.execPath, ['--version']);
console.log(`Node.js version: ${stdout.trim()}`);process.execPath is the full path to the node program. The example runs it with --version and prints, for example, "Node.js version: v22.12.0". stdout is what the program printed.
Running your own script
Another script is started the same way, with arguments:
import { execFile } from 'node:child_process';
import { writeFile } from 'node:fs/promises';
import { promisify } from 'node:util';
const run = promisify(execFile);
await writeFile('count.mjs', 'console.log(process.argv.slice(2).length);');
const { stdout } = await run(process.execPath, ['count.mjs', 'a', 'b', 'c']);
console.log(`Arguments: ${stdout.trim()}`); // Arguments: 3The example first creates a tiny script count.mjs, then runs it as a separate program.
An error in the child process
If the program exits with a code other than 0, the promise rejects. The error holds the exit code and everything the program printed:
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const run = promisify(execFile);
try {
await run(process.execPath, ['-e', 'process.exit(3)']);
} catch (error) {
console.log(`The program exited with code ${error.code}`); // 3
}spawn: long commands
spawn() does not collect output but passes it on as it appears. The option stdio: 'inherit' prints everything straight to your terminal — handy for builds or package installs:
// scripts/backup.js
import { spawn } from 'node:child_process';
const child = spawn('git', ['log', '--oneline', '-5'], { stdio: 'inherit' });
child.on('close', (code) => {
console.log(`git exited with code ${code}`);
});node scripts/backup.js shows the project's last five commits and then the exit code.
| Function | When to use |
|---|---|
execFile() | Short output needed in full |
spawn() | Long work, large output |
exec() | A shell string with && or redirection is needed |
Common mistake
exec() runs a string through the command shell. If you insert user data into it, the user can append a command of their own:
// src/server.js
// Dangerous: exec(`convert ${fileName} out.png`)
// fileName = 'a.jpg; rm -rf ~' runs a second commandUse execFile() or spawn() with an array of arguments: each argument is passed to the program as is and is not parsed by the shell.