# ⏳️ Streams
## Node.js streams
### Input
```js
import {createReadStream} from 'node:fs';
import {once} from 'node:events';
import {execa} from 'execa';
const readable = createReadStream('input.txt');
await once(readable, 'open');
await execa({stdin: readable})`npm run scaffold`;
```
### Output
```js
import {createWriteStream} from 'node:fs';
import {once} from 'node:events';
import {execa} from 'execa';
const writable = createWriteStream('output.txt');
await once(writable, 'open');
await execa({stdout: writable})`npm run build`;
```
### File descriptors
When passing a Node.js stream to the [`stdin`](api.md#optionsstdin), [`stdout`](api.md#optionsstdout) or [`stderr`](api.md#optionsstderr) option, that stream must have an underlying file or socket, such as the streams created by the [`fs`](https://nodejs.org/api/fs.html#filehandlecreatereadstreamoptions), [`net`](https://nodejs.org/api/net.html#new-netsocketoptions) or [`http`](https://nodejs.org/api/http.html#class-httpincomingmessage) core modules. Otherwise the following error is thrown.
```
TypeError [ERR_INVALID_ARG_VALUE]: The argument 'stdio' is invalid.
```
This limitation can be worked around by either:
- Using the [`input`](api.md#optionsinput) option instead of the [`stdin`](api.md#optionsstdin) option.
- Passing a [web stream](#web-streams).
- Passing [`[nodeStream, 'pipe']`](output.md#multiple-targets) instead of `nodeStream`.
## Web streams
[Web streams](https://nodejs.org/api/webstreams.html) ([`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) or [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream)) can be used instead of [Node.js streams](https://nodejs.org/api/stream.html).
```js
const response = await fetch('https://example.com');
await execa({stdin: response.body})`npm run build`;
```
## Iterables as input
```js
const getReplInput = async function * () {
for await (const replLine of getReplLines()) {
yield replLine;
}
};
await execa({stdin: getReplInput()})`npm run scaffold`;
```
## Manual streaming
[`subprocess.stdin`](api.md#subprocessstdin) is a Node.js [`Readable`](https://nodejs.org/api/stream.html#class-streamreadable) stream and [`subprocess.stdout`](api.md#subprocessstdout)/[`subprocess.stderr`](api.md#subprocessstderr)/[`subprocess.all`](api.md#subprocessall) are Node.js [`Writable`](https://nodejs.org/api/stream.html#class-streamwritable) streams.
They can be used to stream input/output manually. This is intended for advanced situations. In most cases, the following simpler solutions can be used instead:
- [`result.stdout`](output.md#stdout-and-stderr), [`result.stderr`](output.md#stdout-and-stderr) or [`result.stdio`](output.md#additional-file-descriptors).
- The [`stdin`](api.md#optionsstdin), [`stdout`](api.md#optionsstdout), [`stderr`](api.md#optionsstderr) or [`stdio`](api.md#optionsstdio) options.
- [`subprocess.iterable()`](lines.md#progressive-splitting).
- [`subprocess.pipe()`](pipe.md).
## Converting a subprocess to a stream
### Convert
The [`subprocess.readable()`](api.md#subprocessreadablereadableoptions), [`subprocess.writable()`](api.md#subprocesswritablewritableoptions) and [`subprocess.duplex()`](api.md#subprocessduplexduplexoptions) methods convert the subprocess to a Node.js [`Readable`](https://nodejs.org/api/stream.html#class-streamreadable), [`Writable`](https://nodejs.org/api/stream.html#class-streamwritable) and [`Duplex`](https://nodejs.org/api/stream.html#class-streamduplex) stream.
This is useful when using a library or API that expects Node.js streams as arguments. In every other situation, the simpler solutions described [above](#manual-streaming) can be used instead.
```js
const readable = execa`npm run scaffold`.readable();
const writable = execa`npm run scaffold`.writable();
const duplex = execa`npm run scaffold`.duplex();
```
### Different file descriptor
By default, [`subprocess.readable()`](api.md#subprocessreadablereadableoptions), [`subprocess.writable()`](api.md#subprocesswritablewritableoptions) and [`subprocess.duplex()`](api.md#subprocessduplexduplexoptions) methods use [`stdin`](api.md#subprocessstdin) and [`stdout`](api.md#subprocessstdout). This can be changed using the [`from`](api.md#readableoptionsfrom) and [`to`](api.md#writableoptionsto) options.
```js
const readable = execa`npm run scaffold`.readable({from: 'stderr'});
const writable = execa`npm run scaffold`.writable({to: 'fd3'});
const duplex = execa`npm run scaffold`.duplex({from: 'stderr', to: 'fd3'});
```
Writing to an additional file descriptor like `'fd3'` requires marking it as [input](input.md#additional-file-descriptors), since it otherwise defaults to output.
```js
const subprocess = execa({stdio: ['pipe', 'pipe', 'pipe', {value: 'pipe', input: true}]})`npm run scaffold`;
const writable = subprocess.writable({to: 'fd3'});
```
### Error handling
When using [`subprocess.readable()`](api.md#subprocessreadablereadableoptions), [`subprocess.writable()`](api.md#subprocesswritablewritableoptions) or [`subprocess.duplex()`](api.md#subprocessduplexduplexoptions), the stream waits for the subprocess to end, and emits an [`error`](https://nodejs.org/api/stream.html#event-error) event if the subprocess [fails](errors.md). This differs from [`subprocess.stdin`](api.md#subprocessstdin), [`subprocess.stdout`](api.md#subprocessstdout) and [`subprocess.stderr`](api.md#subprocessstderr)'s behavior.
This means you do not need to `await` the subprocess' [promise](execution.md#result). On the other hand, you (or the library using the stream) do need to both consume the stream, and handle its `error` event. This can be done by using [`await finished(stream)`](https://nodejs.org/api/stream.html#streamfinishedstream-options), [`await pipeline(..., stream, ...)`](https://nodejs.org/api/stream.html#streampipelinesource-transforms-destination-options) or [`await text(stream)`](https://nodejs.org/api/webstreams.html#streamconsumerstextstream) which throw an exception when the stream errors.
## Converting a subprocess to a web stream
The [`subprocess.readableStream()`](api.md#subprocessreadablestreamreadableoptions), [`subprocess.writableStream()`](api.md#subprocesswritablestreamwritableoptions) and [`subprocess.transformStream()`](api.md#subprocesstransformstreamduplexoptions) methods are the [web streams](#web-streams) counterparts of [`subprocess.readable()`](api.md#subprocessreadablereadableoptions), [`subprocess.writable()`](api.md#subprocesswritablewritableoptions) and [`subprocess.duplex()`](api.md#subprocessduplexduplexoptions). They behave the same way, including [error handling](#error-handling) and the [`from`](api.md#readableoptionsfrom)/[`to`](api.md#writableoptionsto) options, but return a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream), a [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) and a [`{readable, writable}`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) pair instead of Node.js streams.
This is useful when using a library or API that expects web streams as arguments. In every other situation, the [Node.js stream methods](#converting-a-subprocess-to-a-stream) can be used instead.
```js
const readableStream = execa`npm run scaffold`.readableStream();
const writableStream = execa`npm run scaffold`.writableStream();
const {readable, writable} = execa`npm run scaffold`.transformStream();
```
[**Next**: 📞 Inter-process communication](ipc.md)\
[**Previous**: 🔀 Piping multiple subprocesses](pipe.md)\
[**Top**: Table of contents](../readme.md#documentation)