concat-stream
A tiny writable stream that buffers everything written to it and hands you back a single Buffer, string, or array.
Repository Health
Technical Analysis
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
encodingoption — 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.
Used by 3 apps in this directory
Convex Backend
Developer Tools · Databases
Open-source reactive database that lets developers build live-updating apps with pure TypeScript, strong consistency, and real-time subscriptions—no separate API layer required.
LobeHub
AI Assistants · Productivity · Automation
Your Chief Agent Operator — build, schedule, and collaborate with an entire AI team in one self-hostable workspace.
Postiz
Social Media · Automation
The agentic social media scheduler — AI-powered content creation, 33-platform posting, and team workflows, all self-hosted.