The stdout and stderr options redirect the subprocess output. They default to 'pipe', which returns the output using result.stdout and result.stderr.
import {execa} from 'execa';
const {stdout, stderr} = await execa`npm run build`;
console.log(stdout);
console.log(stderr);const {stdout, stderr} = await execa({stdout: 'ignore'})`npm run build`;
console.log(stdout); // undefined
console.log(stderr); // string with errorsawait execa({stdout: {file: 'output.txt'}})`npm run build`;
// Or:
await execa({stdout: new URL('file:///path/to/output.txt')})`npm run build`;// Redirect interleaved stdout and stderr to same file
const output = {file: 'output.txt'};
await execa({stdout: output, stderr: output})`npm run build`;// Append instead of overwriting
await execa({stdout: {file: 'output.txt', append: true}})`npm run build`;The parent process' output can be re-used in the subprocess by passing 'inherit'. This is especially useful to print to the terminal in command line applications.
await execa({stdout: 'inherit', stderr: 'inherit'})`npm run build`;To redirect from/to a different file descriptor, pass its number or process.stdout/process.stderr.
// Print both stdout/stderr to the parent stdout
await execa({stdout: process.stdout, stderr: process.stdout})`npm run build`;
// Or:
await execa({stdout: 1, stderr: 1})`npm run build`;If the subprocess uses Node.js, IPC can be used to return almost any type from the subprocess. The result.ipcOutput array contains all the messages sent by the subprocess.
// main.js
import {execaNode} from 'execa';
const {ipcOutput} = await execaNode`build.js`;
console.log(ipcOutput[0]); // {kind: 'start', timestamp: date}
console.log(ipcOutput[1]); // {kind: 'stop', timestamp: date}// build.js
import {sendMessage} from 'execa';
await sendMessage({kind: 'start', timestamp: new Date()});
await runBuild();
await sendMessage({kind: 'stop', timestamp: new Date()});The output can be redirected to multiple targets by setting the stdout or stderr option to an array of values.
The following example redirects stdout to both the terminal and an output.txt file, while also retrieving its value programmatically.
const {stdout} = await execa({stdout: ['inherit', {file: 'output.txt'}, 'pipe']})`npm run build`;
console.log(stdout);Loss of TTY control: Please note that when a file descriptor is configured with a combination of 'inherit' and other values, this file descriptor will never refer to a TTY in the subprocess, even if in the current process it does.
If the all option is true, stdout and stderr are combined:
stdout and stderr are guaranteed to interleave. However, for performance reasons, the subprocess might buffer and merge multiple simultaneous writes to stdout or stderr. This can prevent proper interleaving.
For example, this prints 1 3 2 instead of 1 2 3 because both console.log() are merged into a single write.
const {all} = await execa({all: true})`node example.js`;// example.js
console.log('1'); // writes to stdout
console.error('2'); // writes to stderr
console.log('3'); // writes to stdoutThis can be worked around by using setTimeout().
import {setTimeout} from 'timers/promises';
console.log('1');
console.error('2');
await setTimeout(0);
console.log('3');Some options are related to the subprocess output: verbose, lines, stripFinalNewline, buffer, maxBuffer. By default, those options apply to all file descriptors (stdout, stderr, and others) and IPC messages. A plain object can be passed instead to apply them to only stdout, stderr, all (both stdout and stderr), ipc, fd3, etc.
// Same value for stdout and stderr
await execa({verbose: 'full'})`npm run build`;
// Different values for stdout and stderr
await execa({verbose: {stdout: 'none', stderr: 'full'}})`npm run build`;The stdio option is an array combining stdin, stdout, stderr and any other file descriptor. It is useful when using additional file descriptors beyond the standard ones, either for input or output.
result.stdio can be used to retrieve some output from any file descriptor, as opposed to only stdout and stderr.
// Retrieve output from file descriptor number 3
const {stdio} = await execa({
stdio: ['pipe', 'pipe', 'pipe', 'pipe'],
})`npm run build`;
console.log(stdio[3]);The stdio option can also be a single value 'pipe', 'overlapped', 'ignore' or 'inherit'. This is a shortcut for setting that same value with the stdin, stdout and stderr options.
await execa({stdio: 'ignore'})`npm run build`;
// Same as:
await execa({stdin: 'ignore', stdout: 'ignore', stderr: 'ignore'})`npm run build`;To prevent high memory consumption, a maximum output size can be set using the maxBuffer option. It defaults to 100MB.
When this threshold is hit, the subprocess fails and error.isMaxBuffer becomes true. The truncated output is still available using error.stdout, error.stderr and error.ipcOutput.
This is measured:
- By default: in characters.
- If the
encodingoption is'buffer': in bytes. - If the
linesoption istrue: in lines. - If a transform in object mode is used: in objects.
- With
error.ipcOutput: in messages.
try {
await execa({maxBuffer: 1_000_000})`npm run build`;
} catch (error) {
if (error.isMaxBuffer) {
console.error('Error: output larger than 1MB.');
console.error(error.stdout);
console.error(error.stderr);
}
throw error;
}When the buffer option is false, result.stdout, result.stderr, result.all, result.stdio[*] and result.ipcOutput properties are empty.
This prevents high memory consumption when the output is big. However, the output must be either ignored, redirected, streamed or listened to. If streamed, this should be done right away to avoid missing any data.