concat-stream

A tiny writable stream that buffers everything written to it and hands you back a single Buffer, string, or array.

Library
npm
v2.0.0
576stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
36/100Needs Attention
Development Activity0
Maintenance0
Community64
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
53/100Fair
Architecture68
Code Quality62
Innovation58
Learning Curve25

concat-stream is a lightweight writable stream for Node.js that collects every chunk written to it — strings, Buffers, arrays, or Uint8Arrays — and calls back once with the fully concatenated result. It’s a common building block in the Node.js streaming ecosystem for cases where you need to work with a stream’s output as a single value rather than processing it incrementally.

Under the hood it infers the output type from the first chunk written (or honors an explicit encoding option), then reassembles the accumulated pieces into a Buffer, string, array, or Uint8Array using dedicated concatenation helpers. Its small surface area and zero-config defaults have made it a long-standing dependency across the npm ecosystem, from build tools to HTTP clients.

What You Get

  • A drop-in Writable stream — pipe any readable into it like any other Node.js stream target.
  • Automatic output-type inference — get back a Buffer, string, array, or Uint8Array without configuring anything.
  • An explicit encoding option — force the result to a specific type (string, buffer, array, uint8array, object) instead of relying on inference.
  • Mixed-input handling — accepts writes of different types (strings, Buffers, arrays, typed arrays) in the same stream and normalizes them into one coherent result.

Common Use Cases

  • Buffering an HTTP response body before parsing it as JSON or text.
  • Collecting the full output of a child process’s stdout/stderr stream for logging or testing.
  • Reading an entire file stream into memory when the file is small enough to fit in a single Buffer.
  • Aggregating chunked data from a transform pipeline before handing it to a synchronous API.

Under The Hood

Architecture The module is a single file exporting one constructor, ConcatStream, which extends Node’s Writable stream (via the readable-stream package for consistent behavior across Node versions) using classic prototype-based inheritance from the inherits package. Data flows in one direction: callers pipe or write into the instance, _write pushes each chunk onto an internal body array and calls next(), and on the stream’s finish event the optional callback fires with the result of getBody(), which infers (or honors an explicit) encoding and concatenates the buffered chunks via one of four dedicated helpers — stringConcat, bufferConcat, arrayConcat, and u8Concat. There is no external state or async I/O beyond the stream lifecycle itself; the core abstraction is the encoding-inference-plus-concatenation step, and every downstream consumer’s return-type guarantee depends on that logic staying correct.

Tech Stack The package is plain, un-transpiled JavaScript with no build step, targeting Node.js directly. Its runtime dependencies are readable-stream (a userland backport of Node’s stream implementation for cross-version consistency), inherits (a minimal prototype-inheritance helper), buffer-from (a safe Buffer.from shim for older Node releases), and typedarray (a Uint8Array polyfill for environments that lack one). Testing runs on tape, a TAP-based assertion library, invoked via test/*.js test/server/*.js, with legacy continuous integration configured through a .travis.yml file.

Code Quality The test/ directory holds focused, table-driven-style test files (array.js, buffer.js, infer.js, nothing.js, objects.js, string.js, typedarray.js, plus a server/ subfolder) using tape’s plan()-based assertions to cover encoding inference, mixed-input-type handling, multibyte string reassembly, and empty-stream edge cases. There are no TypeScript types, no linter configuration, and no modern CI beyond the legacy Travis setup; error handling is deliberately absent from the module itself — the README explicitly states callers must handle stream errors themselves, consistent with general Node.js stream conventions. Naming is consistent and the codebase is easy to read despite predating ES6 class syntax.

API Design The public API is a single factory function, concat(opts, cb), callable with or without new, that infers the desired output type automatically so the common case needs zero configuration — readStream.pipe(concat(cb)) is the entire integration. An explicit encoding option covers every supported type when inference isn’t desired. This isn’t a novel technique — it’s a well-worn convenience wrapper that’s been copied and depended on widely (it’s part of the mississippi stream-utility collection) — but its minimal API surface and sensible defaults keep boilerplate to a minimum.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search