readable.toArray()
Collect every chunk of a stream into a single array.
readable.toArray([options])- Added in Node.js v17.5.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$optionsoptional | Object | Options for the operation. |
$options.signaloptional | AbortSignal | Allows cancelling the toArray operation if the signal is aborted. |
Return value
PromiseA promise that fulfills with an array containing all the data from the stream.
Errors
Rejects with the stream's error if the stream fails, and with an AbortError if the signal option is aborted before the stream completes.
Changelog
- PHP v17.5.0Added, alongside a v16.15.0 backport. Marked Stability 1 - Experimental.
toArray() reads a stream to completion and resolves with every chunk it produced, in order. It is the shortest way to turn a stream back into a value, and it pairs naturally with the other iterator helpers — map(), filter(), take() — which return streams that toArray() then collapses.
When to reach for it
Tests, scripts, and small known-size inputs. Asserting on the output of a pipeline is far easier when you can compare against an array, and reading a small config file or a fixture is not worth a sink stream. It is also the natural terminator for a .map(fn, { concurrency: n }) chain, where the point is the collected results.
What trips people up
It defeats the purpose of streaming. Every chunk is held in memory simultaneously, so a large file or an open socket will grow the heap until the process dies. The official docs are blunt about this: it is for interoperability and convenience, not the primary way to consume streams. If you cannot state an upper bound on the input, do not use it.
Chunk boundaries are also not meaningful on a byte stream — adjacent push() calls may be merged into one Buffer. Use Buffer.concat(await stream.toArray()) rather than assuming one array entry per write.
The API is still marked experimental.
Example
When to use it
- Assert on the exact output of a transform stream in a unit test
- Collect the results of a concurrent .map() over a stream of IDs
- Read a small fixture or config file without writing a sink
- Inspect what a pipeline stage produced while debugging
Frequently asked questions
How do I read an entire stream into an array in Node.js?
Await readable.toArray(), which resolves with every chunk in order. Use it only when the input size is bounded, because it holds the whole stream in memory.
Is readable.toArray() safe for large files?
No — it buffers the complete stream in memory and will exhaust the heap on a large file or an open socket. Process the stream with pipeline() or for await instead when the size is unbounded.
Why does toArray() return Buffers instead of strings?
Because a stream not in object mode emits Buffers. Use Buffer.concat(await stream.toArray()).toString(), or set the encoding option on the stream, to get text.
More examples
Terminating a concurrent map
The stream helpers keep at most three requests in flight, and toArray() waits for the whole chain to finish before resolving. Order is preserved: results come back in the order the IDs were emitted, not the order the responses arrived. Because the input length is known and small, holding every result in memory is safe here.
import { Readable } from 'node:stream';
const ids = Readable.from([1, 2, 3, 4, 5, 6]);
// map() returns a stream; toArray() collects it once every task settles.
const results = await ids
.map(async (id) => {
const res = await fetch(`https://api.example.com/items/${id}`);
return res.json();
}, { concurrency: 3 })
.filter((item) => item.inStock)
.toArray();
console.log('in stock:', results.length);Reading a response body in a test
A PassThrough is used as the pipeline's destination purely so its contents can be collected afterwards. This is the main legitimate use of toArray(): the input is a fixture of known size, so the memory cost is bounded and comparing arrays is far clearer than accumulating chunks by hand.
import { pipeline } from 'node:stream/promises';
import { Readable, Transform } from 'node:stream';
import assert from 'node:assert';
const redact = new Transform({
objectMode: true,
transform(row, encoding, callback) {
callback(null, { ...row, token: '***' });
},
});
const collected = new (require('node:stream').PassThrough)({ objectMode: true });
await pipeline(
Readable.from([{ id: 1, token: 'secret' }, { id: 2, token: 'hunter2' }]),
redact,
collected,
);
// Only safe because the fixture is a fixed, tiny array.
assert.deepStrictEqual(await collected.toArray(), [
{ id: 1, token: '***' },
{ id: 2, token: '***' },
]);
console.log('assertion passed');
Discussion