base64-stream

Streaming Base64 encoder and decoder Transform classes for Node.js, so binary data can be converted on the fly instead of buffered in memory.

Library
npm
v1.0.0
119stars
MIT License

Repository Health

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

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
53/100Fair
Architecture78
Code Quality58
Innovation40
Learning Curve35

base64-stream is a small Node.js library that exposes two Transform stream classes, Base64Encode and Base64Decode, for converting between binary data and Base64 text as it flows through a pipe. Instead of loading a whole payload into memory to run it through Node’s built-in Buffer.toString('base64') / Buffer.from(str, 'base64') conversions, you pipe a readable stream through these classes and get Base64 (or binary) output incrementally, chunk by chunk.

Both classes handle the awkward part of streaming Base64 correctly: encoding only works cleanly in groups of 3 bytes and decoding only works cleanly in groups of 4 characters, so each class buffers the leftover bytes/characters between _transform calls and flushes them at the end of the stream. Base64Encode additionally supports a configurable lineLength (for wrapping output, e.g. MIME-style) and a prefix string (useful for building data: URIs on the fly), plus inputEncoding/outputEncoding options for non-default Buffer encodings.

What You Get

  • Base64Encode — a Transform stream that converts binary (or string) input chunks into a Base64 text stream
  • Base64Decode — a Transform stream that converts a Base64 text/Buffer stream back into binary Buffers
  • Correct boundary handling across chunks (3-byte groups for encoding, 4-character groups for decoding), so multi-chunk streams never emit corrupted Base64
  • Optional line-length wrapping and string prefixing on the encoder, plus configurable input/output encodings on both classes

Common Use Cases

  • Proxying a remote image through an HTTP server as a base64 data: URI without buffering the full file
  • Piping Base64-encoded data on stdin through Base64Decode to produce raw binary on stdout
  • Wrapping Base64 attachment data at a fixed line length for MIME/email encoding
  • Encoding or decoding very large files incrementally instead of loading them entirely into memory

Under The Hood

Architecture The entire library is two small files (lib/encode.js, lib/decode.js) re-exported from index.js, each extending Node’s built-in stream.Transform and overriding only _transform/_flush — there’s no dependency injection, no internal layering, and no abstraction beyond the Transform contract itself. Base64Encode buffers any leftover bytes not divisible by 3 in this.extra, converts the rest via Buffer.toString('base64'), and optionally reformats the string through a private _fixLineLength helper before pushing; Base64Decode mirrors this by stripping newlines, buffering leftover characters not divisible by 4, and converting back via Buffer.from(str, 'base64'). Because the whole implementation sits in two symmetric files with a single shared concern (chunk-boundary bookkeeping), the design is easy to reason about end-to-end, though it also means there is effectively nothing to “break” architecturally beyond the Transform contract.

Tech Stack Plain JavaScript (no TypeScript, no transpilation step) targeting Node’s native stream module; package.json declares no runtime dependencies at all, only mocha and should as devDependencies for testing, and no bundler, ORM, or web framework is involved since the whole surface area is two stream classes.

Code Quality Both stream classes carry JSDoc comments on their public constructor options and lifecycle methods, and the test/ directory has fairly extensive Mocha + should specs covering single-chunk input, multi-chunk input at various boundary alignments, custom input/output encodings, line-length wrapping, and prefixing. There is no CI configuration, linter configuration, or TypeScript in the repository, and neither _transform implementation ever passes an error to its callback, so malformed input would surface as an uncaught synchronous exception rather than a stream error event.

What Makes It Unique The library doesn’t introduce a novel encoding algorithm — it applies the standard Node Transform pattern to Base64 conversion, which is a well-understood technique. Its practical value is in already having solved the fiddly chunk-boundary math correctly and exposing a couple of convenience options (line wrapping, prefixing, alternate encodings) that make it usable directly for MIME-style output or data-URI construction without every consumer re-deriving the leftover-byte bookkeeping themselves.

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