stream.Readable.from()

Build a readable stream from any array, iterable, or async generator.

Signature
stream.Readable.from(iterable[, options])
  • Added in Node.js v12.3.0

Parameters

ParameterTypeDescription
$iterableIterable | AsyncIterableObject implementing the Symbol.asyncIterator or Symbol.iterator iterable protocol. Emits an 'error' event if a null value is passed.
$optionsoptionalObjectOptions provided to new stream.Readable([options]). By default Readable.from() sets options.objectMode to true, unless explicitly opted out by setting options.objectMode to false.

Return value

stream.ReadableA readable stream that emits one chunk per value produced by the iterable.

Errors

Emits an 'error' event rather than throwing when a null value is passed as the iterable; an iterable of promises that reject may produce unhandled rejections.

Changelog

  • PHP v12.3.0Added, alongside a v10.17.0 backport.

Readable.from() turns any iterable into a readable stream: an array, a Set, a Map, a generator, or an async generator. It is the shortest correct way to get a stream when the data is already in memory or is produced by a function, and it replaces almost every hand-written Readable subclass.

When to reach for it

Testing is the biggest use. A pipeline() that normally starts with fs.createReadStream() can start with Readable.from(['line1\n', 'line2\n']) instead, giving a deterministic source with no filesystem involved. It is also the adapter that lets an async function* — pagination over an API, a database cursor — be consumed by anything expecting a stream.

What trips people up

Object mode is on by default, which is the opposite of every other Readable. That is usually what you want, since values arrive as-is rather than as Buffers, but it means Readable.from(['a','b']).pipe(fs.createWriteStream(...)) behaves differently from a byte stream, and the stream's highWaterMark counts objects rather than bytes.

The other surprise: strings and Buffers are not iterated. Readable.from('hello') emits 'hello' as a single chunk, not five characters — a deliberate performance choice, not a bug.

Backpressure works normally; the generator is only pulled from as the consumer reads.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Feed fixture data into a pipeline in a unit test without touching the filesystem
  • Expose an async generator over a paginated API as a stream
  • Convert an array of database rows into a stream for a CSV writer
  • Build a deterministic source when reproducing a streaming bug

Frequently asked questions

How do I turn an array into a readable stream in Node.js?

Call stream.Readable.from(array); it returns an object-mode readable that emits one chunk per element. The same call works for any iterable or async generator.

Why does Readable.from('hello') emit one chunk instead of five characters?

Strings and Buffers are deliberately not iterated, for performance and to match the semantics of other streams. Pass an array of characters if you want them one at a time.

Is Readable.from in object mode by default?

Yes, Readable.from() sets objectMode to true unless you explicitly pass objectMode: false, which is the opposite of the plain Readable constructor.

More examples

Streaming a paginated API into a file

The generator does not fetch every page up front. Readable.from() pulls the next value only when the destination has room, so a slow disk throttles the API calls instead of buffering the whole dataset in memory. Prints "written" once the last page has been flushed.

Example · javascript
import { Readable } from 'node:stream';
import { pipeline } from 'node:stream/promises';
import fs from 'node:fs';

async function* fetchAllUsers() {
  let page = 1;
  while (true) {
    const res = await fetch(`https://api.example.com/users?page=${page}`);
    const { items, hasMore } = await res.json();
    for (const item of items) {
      yield JSON.stringify(item) + '\n';
    }
    if (!hasMore) return;
    page += 1;
  }
}

// The generator is only advanced as fast as the file can be written,
// so pagination naturally respects backpressure.
await pipeline(
  Readable.from(fetchAllUsers()),
  fs.createWriteStream('users.ndjson'),
);

console.log('written');

Opting out of object mode for byte output

Prints "object mode: string a" and "object mode: string b", then "byte mode: true a" and "byte mode: true b". Passing objectMode: false is how you get a source that behaves like fs.createReadStream() when a downstream stream expects Buffers.

Example · javascript
const { Readable } = require('node:stream');

// Default: object mode, chunks arrive exactly as given.
const objects = Readable.from(['a', 'b']);

// Byte mode: values are converted to Buffers as in a normal stream.
const bytes = Readable.from(['a', 'b'], { objectMode: false });

objects.on('data', (c) => console.log('object mode:', typeof c, c));
bytes.on('data', (c) => console.log('byte mode:', Buffer.isBuffer(c), c.toString()));

Discussion

  • Be the first to comment on this lesson.