mrkeyoor.com_
Wed 23 Sept 00:32 UTC
npmUtilsupdated 22 Sept 2026

parallel-transform review

parallel-transform 1.2.0 is a callback-based Node Transform stream that keeps several async operations in flight while preserving input order by default. Set `ordered: false` to emit completed results immediately. It uses object mode unless disabled and treats a successful `null` or `undefined` result as a filtered item. This is concurrency on the event loop, not CPU execution across threads. Release 1.2.0 only upgrades `cyclist` to 1.0.1 so every dependency carries proper license metadata; the stream API itself did not change.

Verdict

parallel-transform 1.2.0 installed in 0.7 seconds and occupied 1 MB with 0 audit findings in our sandbox, but it ships 2019-era callback and `readable-stream` 2 semantics. Keep it for proven ordered I/O streams; use a promise-native concurrency tool or current custom Transform for new code.

We installed it

Lab card: what happened when we installed parallel-transformScreenshot of parallel-transform documentation
Install✓ · 0.7s10 packages on disk · 1 MB
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does parallel-transform install cleanly?

Yes. In a fresh container with an empty cache, npm install parallel-transform finished in 0.7s, leaving 10 packages and 1 MB on disk. npm audit reported no known vulnerabilities.

Can parallel-transform run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does parallel-transform work with both ESM and CommonJS?

Yes. Both import 'parallel-transform' and require('parallel-transform') worked in Node 22 in our run. The package is published as CommonJS.

Does parallel-transform include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

parallel-transform or through2-concurrent: which should you use?

through2-concurrent: Use it for a similar callback-based concurrent transform with through2 conventions. parallel-transform 1.2.0 installed in 0.7 seconds and occupied 1 MB with 0 audit findings in our sandbox, but it ships 2019-era callback and readable-stream 2 semantics.

When should you not use parallel-transform?

The work is CPU-bound; all callbacks still run on one Node event loop and no worker thread is created

API stability4/5The constructor overloads, callback worker, ordered default, `ordered: false`, object-mode default, and stream-option position have stayed unchanged since before 1.2.0. That is a predictable surface for old pipelines. The deduction comes from behavior frozen around `readable-stream` 2 and a custom `destroy()` that only emits close, instead of the cancellation and error conventions developers expect from current Node streams. Invalid concurrency also has no documented validation contract.
Docs2/5The README demonstrates ordered concurrency, explains the first argument, shows binary mode, and names the unordered option. It does not document the minimum valid concurrency, the callback-once requirement, `null` filtering, promise incompatibility, the default high-water mark of at least 16, error shutdown, head-of-line memory growth, or absence of cancellation. The core example is enough to start, while production behavior requires reading the roughly 80-line implementation.
Maintenance1/5npm published 1.2.0 on September 5, 2019. That release only moved `cyclist` to 1.0.1 for complete dependency license metadata. GitHub records the last push on June 14, 2024 for a security policy, does not mark the repository archived, and currently shows 5 issues and pull requests combined. No package release has updated its module format, declarations, callback-only worker, cancellation story, or `readable-stream` 2 dependency.
Ecosystem3/5The npm endpoint counted 4,076,940 downloads for the week ending August 24, 2026, while GitHub reports 80 stars. Its Node Transform shape still slots into many older build and ingestion chains, which likely explains the continuing transitive volume. The package has no promise, AbortSignal, worker-thread, Web Stream, observable, or TypeScript adapter. Modern concurrency usage has largely shifted toward async iterables and promise tools such as `p-map`.

Use it if

  • A maintained legacy pipeline already speaks callback-style Node streams
  • Each input starts independent I/O and a fixed concurrency ceiling protects the downstream service
  • Output must remain in source order even when later operations finish sooner
  • Returning `null` as a successful result is a useful object-stream filter
Skip it if

Setup reality

Our parallel-transform 1.2.0 install completed in 0.7 seconds in a fresh Node 22 container. It left 10 packages using 1 MB on disk, and npm audit reported 0 known vulnerabilities. The package measured 20 KB unpacked with 3 direct dependencies and 0 peer dependencies. require() and ESM import both loaded the CommonJS entry, which has no exports map. We found no TypeScript declarations.

Pass a positive integer concurrency and an error-first callback. The constructor does not validate that limit, so 0, a fraction, or a nonnumber can break its scheduling. Object mode defaults on. If highWaterMark is absent, the implementation uses at least 16 and raises it to the concurrency value when that is larger, which can increase upstream buffering along with active work.

Every worker must call its callback once. A returned promise is invisible, a missing callback stalls the stream, and a second callback corrupts completion accounting. A callback error emits error, ends readable output, and closes the transform. Use stream.pipeline() or install listeners. Successful null and undefined results are consumed as filters, so neither value can pass through as object data.

Ordered mode stores finished work until the next input position completes. That guarantees order but lets one slow item retain many later results. Unordered mode reduces that wait and gives nondeterministic output. Destroying the stream does not abort HTTP calls, timers, or file operations that workers already started; own AbortControllers if cancellation matters. Our esbuild browser bundle failed on Node stream code, so this belongs in Node pipelines rather than Web Streams or browser code.

Patterns

Run 8 lookups and keep source order ordered-io

const parallel = require('parallel-transform');

const enrich = parallel(8, (record, callback) => {
  lookupOwner(record.ownerId, (error, owner) => {
    if (error) return callback(error);
    callback(null, { ...record, owner });
  });
});

Eight operations can be active, but one slow early record delays emission of every completed record behind it.

Emit whichever job finishes next completion-order

const transform = parallel(8, { ordered: false }, (job, callback) => {
  runJob(job, callback);
});

Completion order is nondeterministic. Do not join these outputs back to inputs by array position.

Transform Buffer chunks binary-mode

const transform = parallel(4, { objectMode: false }, (chunk, callback) => {
  processChunk(chunk, callback);
});

fs.createReadStream('input.bin')
  .pipe(transform)
  .pipe(fs.createWriteStream('output.bin'));

A stream chunk is an arbitrary Buffer boundary. Many compression and parsing formats require shared state across chunks.

Catch a worker failure at the pipeline pipeline-errors

const { pipeline } = require('node:stream');

pipeline(source, transform, destination, (error) => {
  if (error) {
    console.error('pipeline failed:', error);
    process.exitCode = 1;
  }
});

`pipeline` observes the emitted error. Work already started by other callbacks continues unless your application cancels it.

Drop inactive objects filter-items

const activeOnly = parallel(4, (record, callback) => {
  if (!record.active) return callback(null, null);
  callback(null, record);
});

A successful `null` or `undefined` disappears from the output instead of becoming an object-mode chunk.

Bridge an async worker to one callback promise-adapter

const transform = parallel(6, (item, callback) => {
  Promise.resolve()
    .then(() => enrich(item))
    .then((value) => callback(null, value), callback);
});

Returning the promise is insufficient. Both fulfillment and rejection must reach the callback exactly once.

Use concurrency 1 through the short form serial-form

const normalize = parallel((row, callback) => {
  callback(null, { ...row, name: row.name.trim() });
});

When the first argument is the worker, version 1.2.0 chooses concurrency 1 and still enables object mode.

Set activity and queue limits separately buffer-policy

const transform = parallel(4, {
  objectMode: true,
  highWaterMark: 8,
}, processRecord);

Four is the worker ceiling and 8 is the stream buffer threshold. The package otherwise defaults the latter to at least 16.

Reject a broken worker count validate-limit

const concurrency = Number(process.env.WORKERS ?? 4);
if (!Number.isInteger(concurrency) || concurrency < 1) {
  throw new TypeError('WORKERS must be a positive integer');
}
const transform = parallel(concurrency, worker);

The constructor does not guard `maxParallel`; a zero or invalid value can leave writes waiting indefinitely.

Cancel fetches when the stream closes abort-requests

const active = new Set();
const transform = parallel(5, (item, callback) => {
  const controller = new AbortController();
  active.add(controller);
  fetch(item.url, { signal: controller.signal })
    .then((r) => r.text())
    .then((value) => callback(null, value), callback)
    .finally(() => active.delete(controller));
});
transform.on('close', () => {
  for (const controller of active) controller.abort();
});

Cancellation is application-owned in 1.2.0. Ensure an abort rejection cannot cause a second callback.

Alternatives

PackageRegistryPick it when
through2-concurrentnpmUse it for a similar callback-based concurrent transform with through2 conventions.
concurrent-transformnpmUse it when another small object-stream concurrency helper better matches an existing pipeline.
p-mapnpmUse it when inputs fit an iterable and workers should be promise-native async functions.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.