child_process module
The child_process module is a core Node.js module that enables you to spawn child processes, execute shell commands, and run external programs. It is essential for automating tasks, running build scripts, communicating with system utilities, and creating child processes that share the Node.js runtime. This module provides both asynchronous and synchronous APIs for process management.
Syntax
const { exec, execFile, spawn, fork } = require('child_process'); // CommonJS
import { exec, execFile, spawn, fork } from 'child_process'; // ES modules
exec()
Executes a shell command and buffers the output. The command string is passed to the system shell (/bin/sh on Unix, cmd.exe on Windows), which means you can use shell features like pipes, environment variable expansion, and globbing.
Syntax
exec(command[, options], callback)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
command | string | (required) | The shell command to execute. |
options | object | {} | Configuration object (see below). |
callback | function | (required) | Called with (error, stdout, stderr) when complete. |
Options object:
| Option | Type | Default | Description |
|---|---|---|---|
cwd | string | process.cwd() | Current working directory. |
env | object | process.env | Environment variables. |
shell | string | '/bin/sh' | Shell to use. |
timeout | number | 0 | Timeout in milliseconds (0 = no timeout). |
maxBuffer | number | 1024 * 1024 | Max stdout/stderr size in bytes. |
encoding | string | 'utf8' | Output encoding. |
Example
const { exec } = require('child_process');
exec('ls -la', { cwd: '/tmp' }, (error, stdout, stderr) => {
if (error) {
console.error('Execution error:', error.message);
return;
}
console.log('Output:', stdout);
});
Return Value
Returns a ChildProcess instance. The callback receives stdout and stderr as strings (or buffers if encoding is ‘buffer’).
execFile()
Executes a file directly without spawning a shell. This is safer than exec() when you do not need shell features because it avoids shell injection vulnerabilities. The first argument should be the executable path or filename that will be searched in PATH.
Syntax
execFile(file[, args][, options], callback)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
file | string | (required) | The executable to run. |
args | string[Global_Objects::eval] | [Global_Objects::eval] | Command-line arguments. |
options | object | {} | Configuration object. |
callback | function | (required) | Called with (error, stdout, stderr). |
Example
const { execFile } = require('child_process');
execFile('node', ['--version'], (error, stdout, stderr) => {
if (error) {
console.error('Failed to run node:', error);
return;
}
console.log('Node version:', stdout.trim());
});
Return Value
Returns a ChildProcess instance. Unlike exec(), no shell is involved, so features like pipes or globbing will not work.
spawn()
Spawns a new child process without buffering output. Data is streamed via event listeners, making it ideal for long-running processes or when you need to process output incrementally. This is the most flexible method in the module.
Syntax
spawn(command[, args][, options])
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
command | string | (required) | The command to run. |
args | string[Global_Objects::eval] | [Global_Objects::eval] | Command-line arguments. |
options | object | {} | Configuration object. |
Common options:
| Option | Type | Default | Description |
|---|---|---|---|
cwd | string | process.cwd() | Working directory. |
env | object | process.env | Environment variables. |
stdio | array | ['pipe', 'pipe', 'pipe'] | Standard I/O configuration. |
detached | boolean | false | Run child independently of parent. |
shell | boolean | false | Execute through shell. |
Example
const { spawn } = require('child_process');
const child = spawn('grep', ['-r', 'TODO', './src']);
child.stdout.on('data', (data) => {
console.log('stdout:', data.toString());
});
child.stderr.on('data', (data) => {
console.error('stderr:', data.toString());
});
child.on('close', (code) => {
console.log('Process exited with code:', code);
});
Return Value
Returns a ChildProcess instance with stdout, stderr, and stdin as streams. You listen to ‘data’, ‘close’, and ‘error’ events.
fork()
A special case of spawn() specifically for spawning Node.js modules. The forked process runs as a separate Node.js instance and includes a built-in communication channel (IPC) for message passing between parent and child.
Syntax
fork(modulePath[, args][, options])
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
modulePath | string | (required) | Path to the Node.js module. |
args | string[Global_Objects::eval] | [Global_Objects::eval] | Command-line arguments. |
options | object | {} | Configuration object. |
Key options:
| Option | Type | Default | Description |
|---|---|---|---|
execArgv | string[Global_Objects::eval] | process.execArgv | Node.js flags to pass. |
silent | boolean | false | Pipe stdin/stdout to parent. |
stdio | array | (see docs) | Standard I/O configuration. |
Example
// parent.js
const { fork } = require('child_process');
const child = fork('./child.js');
child.on('message', (msg) => {
console.log('Received from child:', msg);
});
child.send({ action: 'start' });
// child.js
process.on('message', (msg) => {
console.log('Received from parent:', msg);
process.send({ status: 'running' });
});
Return Value
Returns a ChildProcess with an additional send() method and ‘message’ event for IPC communication.
Synchronous Variants
The synchronous variants block the event loop until the child process completes. Use them for simple scripts where async is not necessary.
execSync()
const { execSync } = require('child_process');
const output = execSync('ls -la', { encoding: 'utf8' });
console.log(output);
execFileSync()
const { execFileSync } = require('child_process');
const version = execFileSync('node', ['--version'], { encoding: 'utf8' });
console.log(version);
spawnSync()
const { spawnSync } = require('child_process');
const result = spawnSync('node', ['-e', 'console.log("hello")']);
console.log('stdout:', result.stdout.toString());
console.log('stderr:', result.stderr.toString());
console.log('status:', result.status);
All synchronous variants return a Buffer or string (based on encoding option) and throw on error. Check the status property for exit codes.
Common Patterns
Running a Python script and capturing output
const { execFile } = require('child_process');
execFile('python3', ['script.py', '--input', 'data.txt'],
{ encoding: 'utf8' },
(error, stdout, stderr) => {
if (error) {
console.error('Script failed:', error.message);
return;
}
console.log('Result:', stdout);
}
);
Long-running process with streaming
const { spawn } = require('child_process');
const nginx = spawn('nginx');
nginx.on('error', (err) => {
console.error('Failed to start nginx:', err);
});
process.on('SIGTERM', () => {
nginx.kill();
process.exit(0);
});
Handling timeouts
const { exec } = require('child_process');
const child = exec('sleep 10', { timeout: 2000 }, (error) => {
if (error && error.killed) {
console.log('Process timed out and was killed');
}
});