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 errors
await 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. This also allows specifying multiple inputs with the stdin
option.
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);
When combining 'inherit'
with other values, please note that the subprocess will not be an interactive TTY, even if the current process is one.
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 stdout
This 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
encoding
option is'buffer'
: in bytes. - If the
lines
option 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.