StreamSaver.js

Saves large files and streams straight to disk from the browser without loading them into memory.

Library
npm
v2.0.6
4,367stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
58/100Fair
Development Activity36
Maintenance24
Community72
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
54/100Fair
Architecture60
Code Quality30
Innovation70
Learning Curve55

StreamSaver.js lets web apps write data directly to the user’s filesystem as a stream, instead of buffering everything into memory before triggering a download. It works by spinning up a service worker that impersonates a server: the library pipes bytes to the worker over a MessageChannel (or a transferable ReadableStream in newer browsers), and the worker responds to a matching fetch event with a Content-Disposition header so the browser treats the incoming bytes as a normal file download.

This makes it possible to save gigabyte-scale files - video captures, torrent downloads, zipped archives - from client-side JavaScript without hitting the RAM and blob-size ceilings that libraries like FileSaver.js run into. When a service worker or secure context isn’t available, StreamSaver falls back to buffering into a Blob and triggering a classic anchor-tag download, so the same API keeps working across a wide range of browsers.

What You Get

  • A createWriteStream(filename, options) function that returns a standard WritableStream accepting Uint8Array chunks.
  • A hosted ‘man-in-the-middle’ (mitm.html) plus service worker (sw.js) pair that emulates a server response to trigger real streamed downloads.
  • Automatic fallback to Blob + anchor-tag download when service workers, secure contexts, or streaming support aren’t available (e.g. Safari).
  • Support for transferable streams (a ReadableStream transferred via postMessage) on browsers that implement them, avoiding a slower chunk-by-chunk MessageChannel handoff.
  • A configurable mitm URL so self-hosted deployments can serve their own iframe/service-worker pair instead of the GitHub Pages default.

Common Use Cases

  • Saving a fetch()‘d or torrent-streamed file that’s too large to buffer in memory.
  • Writing a MediaRecorder audio/video capture to disk as it’s recorded.
  • Building an in-browser zip creator that streams entries straight to a .zip file instead of assembling it in memory first.
  • Letting a page write output incrementally as the user types, without holding a growing string in JS memory.

Under The Hood

Architecture StreamSaver.js is a single UMD module exposing createWriteStream, which coordinates with a hosted mitm.html (loaded in a hidden iframe on secure contexts, or a popup on insecure ones) and a service worker (sw.js). When a caller writes to the returned WritableStream, chunks either transfer as a ReadableStream over a MessageChannel (on browsers supporting transferable streams) or get posted chunk-by-chunk; mitm.html forwards the channel to the installed service worker, which registers the incoming stream in a Map keyed by a generated download URL and, on a matching fetch event, responds with a Response wrapping that stream plus Content-Disposition/Content-Length headers - which the browser’s own download manager then saves as a file. Three cooperating contexts (page, iframe/popup, service worker) are bridged entirely through MessageChannel/postMessage rather than any shared module system, making the library effectively a small distributed protocol layered over three browser globals; changing the message shapes passed through channel.port1/port2 (raw chunks, ‘end’, ‘abort’, {download}) requires coordinated updates across StreamSaver.js and sw.js since there’s no shared type contract between them.

Tech Stack The library is vanilla JavaScript with no build step and no runtime dependencies, targeting browser Web APIs directly: WritableStream/ReadableStream/TransformStream (native, or via an optional web-streams-polyfill ponyfill), MessageChannel/postMessage, the Service Worker API (self.onfetch/self.onmessage), and an iframe or window.open popup as the MITM transport. Distribution is via npm (a single StreamSaver.js file as main) alongside a CDN-hosted mitm.html/sw.js pair served from GitHub Pages, which self-hosters can override via streamSaver.mitm. There’s no TypeScript, no bundler, and no linter configuration beyond a single .editorconfig file.

Code Quality No test files or test framework are present anywhere in the repository; the package.json test script is a placeholder that always exits successfully. Error handling relies heavily on try/catch blocks that silently swallow failures to drive feature detection (e.g. probing for transferable-stream support), which is a reasonable pattern for browser capability sniffing but makes real bugs indistinguishable from expected unsupported-browser paths. There’s no CI workflow enforcing any check. Naming is generally clear (createWriteStream, makeIframe, makePopup), though several intentionally deprecated call signatures remain supported inline with console.warn calls rather than being removed.

API Design The public surface is minimal: a single createWriteStream(filename, options) call returns a spec-compliant WritableStream, so anyone comfortable with the standard Streams API can pipe to it with no StreamSaver-specific concepts beyond supplying a filename. Getting started requires including the library (plus, for older browsers, a web-streams-polyfill ponyfill) and calling one function. Naming is consistent (createWriteStream, streamSaver.mitm, streamSaver.version), and the README documents configuration knobs and platform caveats (Safari fallback, insecure-context popups) in real detail, though inline JSDoc coverage is thin and a few deprecated argument shapes remain accepted rather than removed, adding minor surface confusion for newcomers reading the source.

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