downloadjs vs blob-stream vs file-saver vs streamsaver
Client-Side File Generation and Saving Strategies
downloadjsblob-streamfile-saverstreamsaverSimilar Packages:

Client-Side File Generation and Saving Strategies

blob-stream converts streams to Blobs, often for PDFs. downloadjs and file-saver trigger downloads for Blobs or data. streamsaver writes streams directly to disk. Together they cover generating and saving files in the browser.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
downloadjs460,2452,329-509 years agoMIT
blob-stream122,668125-211 years agoMIT
file-saver022,016-2145 years agoMIT
streamsaver0-61.2 kB--MIT

Client-Side File Generation and Saving Strategies

When building web apps that create files — like reports, exports, or media — you need tools to handle data in the browser. blob-stream, downloadjs, file-saver, and streamsaver all help with this, but they work in different ways. Let's compare how they handle data flow, memory, and saving.

📦 Data Flow: Blob vs Stream

The core difference is how data moves through your app. Some tools wait for all data to arrive (Blob), while others handle data in chunks (Stream).

blob-stream collects stream data into a single Blob object.

  • You pipe data into it.
  • It waits until everything is done before giving you a Blob.
// blob-stream: Collects data into a Blob
var stream = blobStream();
doc.pipe(stream);
stream.on('finish', function() {
  var blob = stream.toBlob('application/pdf');
});

downloadjs takes data (Blob or URL) and triggers a download.

  • It expects the data to be ready upfront.
  • Best for small files that load quickly.
// downloadjs: Triggers download for ready data
download(blob, "report.pdf", "application/pdf");

file-saver also expects a complete Blob.

  • It focuses on triggering the browser save dialog.
  • Works well when you already have the full file in memory.
// file-saver: Triggers save dialog for Blob
saveAs(blob, "report.pdf");

streamsaver handles data as it arrives.

  • You write chunks to a stream.
  • The browser saves them to disk immediately without waiting.
// streamsaver: Writes chunks directly to disk
const stream = streamsaver.createWriteStream("report.pdf");
const writer = stream.getWriter();
writer.write(chunk);

🧠 Memory Usage: All at Once vs Chunk by Chunk

Memory management is critical for large files. Loading everything at once can crash the tab.

blob-stream holds the whole file in memory.

  • Good for small PDFs or images.
  • Risky for files over 100MB.
// blob-stream: Holds full Blob in memory
stream.on('finish', function() {
  // Entire file is now in RAM
  var blob = stream.toBlob('application/pdf');
});

downloadjs relies on the input data size.

  • If you pass a large Blob, it stays in memory.
  • No special handling for memory limits.
// downloadjs: No memory optimization
download(largeBlob, "big-file.zip", "application/zip");

file-saver also relies on the input Blob.

  • The browser must hold the Blob before saving.
  • Can cause slowdowns on low-end devices.
// file-saver: No memory optimization
saveAs(largeBlob, "big-file.zip");

streamsaver avoids memory buildup.

  • Data flows to disk as it is generated.
  • Ideal for large exports or video recordings.
// streamsaver: Constant memory usage
const stream = streamsaver.createWriteStream("big-file.zip");
// Write chunks as they are created, not all at once

🛠️ API Simplicity: One Call vs Pipe Setup

Developer experience varies from single functions to stream piping.

blob-stream requires piping logic.

  • You need to understand Node-style streams.
  • More setup but flexible for generation.
// blob-stream: Requires pipe setup
var stream = blobStream();
doc.pipe(stream);

downloadjs is a single function call.

  • Very easy to drop into any project.
  • Less control over the process.
// downloadjs: One function call
download(data, "file.txt", "text/plain");

file-saver is also a single function call.

  • Widely recognized API.
  • Simple for standard save actions.
// file-saver: One function call
saveAs(blob, "file.txt");

streamsaver requires stream writer setup.

  • More code to manage the writer.
  • Necessary for streaming benefits.
// streamsaver: Requires writer setup
const stream = streamsaver.createWriteStream("file.txt");
const writer = stream.getWriter();

🌐 Browser Support: Legacy vs Modern

Compatibility depends on whether you use Blobs or Service Workers.

blob-stream works wherever Blobs work.

  • Very broad support.
  • Depends on the browser's Blob API.
// blob-stream: Broad Blob support
var stream = blobStream();
// Works in most modern browsers

downloadjs uses basic link tricks.

  • Works in almost all browsers.
  • Fallbacks for older Safari versions.
// downloadjs: Broad support
download(data, "file.txt");
// Handles older browser quirks internally

file-saver handles browser quirks for Blobs.

  • Includes fixes for Safari and IE.
  • Stable across many versions.
// file-saver: Handles browser quirks
saveAs(blob, "file.txt");
// Includes polyfills for older browsers

streamsaver needs Service Workers.

  • Requires modern browsers (Chrome, Firefox, Edge).
  • Does not work in older environments.
// streamsaver: Requires Service Workers
const stream = streamsaver.createWriteStream("file.txt");
// Fails if Service Workers are not supported

📌 Summary Table

Featureblob-streamdownloadjsfile-saverstreamsaver
Data TypeStream to BlobData/BlobBlobStream
MemoryHigh (Full Blob)High (Full Blob)High (Full Blob)Low (Chunked)
API StylePipe EventsFunction CallFunction CallStream Writer
Best ForPDF GenerationSimple DownloadsStandard SavesLarge Files
BrowserBroadBroadBroadModern Only

💡 Final Recommendation

blob-stream is best when you are generating binary data like PDFs in the browser and need a Blob output. Pair it with file-saver to trigger the download.

downloadjs is best for quick, simple downloads where you already have the data and want minimal code.

file-saver is best for reliable Blob saving across many browsers. It is the standard choice for general-purpose file saving.

streamsaver is best for large files. If you are exporting huge datasets or recording media, use this to avoid crashing the browser tab.

Final Thought: For small files, file-saver or downloadjs are fine. For large files, streamsaver is the only safe choice. Use blob-stream when you need to create the Blob from a stream first.

How to Choose: downloadjs vs blob-stream vs file-saver vs streamsaver

  • downloadjs:

    Choose downloadjs for simple, small file downloads where you want a single function call without extra setup. It handles data URLs and Blobs with minimal configuration.

  • blob-stream:

    Choose blob-stream when generating binary data like PDFs client-side that need conversion to a Blob first. It is specifically designed to pipe stream data into a Blob object for further handling.

  • file-saver:

    Choose file-saver for standard Blob downloads where consistent save dialog behavior across browsers is needed. It is a stable choice for general-purpose Blob saving.

  • streamsaver:

    Choose streamsaver for large files where loading the entire Blob into memory would cause performance issues or crashes. It streams data directly to the file system.

README for downloadjs

download

========

Summary


The download() function is used to trigger a file download from JavaScript.

It specifies the contents and name of a new file placed in the browser's download directory. The input can be a URL, String, Blob, or Typed Array of data, or via a dataURL representing the file's data as base64 or url-encoded string. No matter the input format, download() saves a file using the specified file name and mime information in the same manner as a server using a Content-Disposition HTTP header.

Getting and Using


Via NPM/Bower

npm install downloadjs
bower install downloadjs

require("downloadjs")(data, strFileName, strMimeType);

Simple global download function via <script> include

download(data, strFileName, strMimeType);

Included via AMD

require(['path/to/file'], function(download) {
    download(data, strFileName, strMimeType);
});

Parameters


  • data - The Blob, File, String, or dataURL containing the soon-to-be File's contents.
  • strFileName - The name of the file to be created. Note that older browsers (like FF3.5, Ch5) don't honor the file name you provide, instead they automatically name the downloaded file.
  • strMimeType - The MIME content-type of the file to download. While optional, it helps the browser present friendlier information about the download to the user, encouraging them to accept the download.

Example Usage


Plain Text

text string - live demo

download("hello world", "dlText.txt", "text/plain");

text dataURL - live demo

download("data:text/plain,hello%20world", "dlDataUrlText.txt", "text/plain");

text blob - live demo

download(new Blob(["hello world"]), "dlTextBlob.txt", "text/plain");

text url - live demo

download("/robots.txt");

text UInt8 Array - live demo

var str= "hello world",	arr= new Uint8Array(str.length);
str.split("").forEach(function(a,b){
  arr[b]=a.charCodeAt();
});

download( arr, "textUInt8Array.txt", "text/plain" );

HTML

html string - live demo

download(document.documentElement.outerHTML, "dlHTML.html", "text/html");

html Blob - live demo

download(new Blob(["hello world".bold()]), "dlHtmlBlob.html", "text/html");

ajax callback - live demo

(note that callback mode won't work on vanilla ajax or with binary files)

$.ajax({
		url: "/download.html",
		success: download.bind(true, "text/html", "dlAjaxCallback.html")
});

Binary Files

image from URL - live demo

download("/diff6.png");

Image via ajax for custom filename - live demo

var x=new XMLHttpRequest();
x.open( "GET", "/diff6.png" , true);
x.responseType="blob";
x.onload= function(e){download(e.target.response, "awesomesauce.png", "image/png");};
x.send();

Compatibility


download.js works with a wide range of devices and browsers.

You can expect it to work for the vast majority of your users, with some common-sense limits:

  • Devices without file systems like iPhone, iPad, Wii, et al. have nowhere to save the file to, sorry.
  • Android support starts at 4.2 for the built-in browser, though chrome 36+ and firefox 20+ on android 2.3+ work well.
  • Devices without Blob support won't be able to download Blobs or TypedArrays
  • Legacy devices (no a[download]) support can only download a few hundred kilobytes of data, and can't give the file a custom name.
  • Devices without window.URL support can only download a couple megabytes of data
  • IE versions of 9 and before are NOT supported because the don't support a[download] or dataURL frame locations.

FAQ


  • Can I tell when a download is done/canceled? No.
  • How can I style the temporary download link? Define CSS class styles for .download-js-link.
  • What's up with Safari? I don't know either but pull requests that improve the situation are welcome.
  • Why is my binary file corrupted? Likely: an incorrect MIME or using jQuery ajax, which has no bin support.
  • How big of files work? Depends, try yourself: File Echo Demo... I do a 1GB dl routinely on a thinkpad...

Change Log (v4.1)


  • 2008 :: landed a FF+Chrome compat way of downloading strings to local un-named files, upgraded to use a hidden frame and optional mime
  • 2012 :: added named files via a[download], msSaveBlob() for IE (10+) support, and window.URL support for larger+faster saves than dataURLs
  • 2014 :: added dataURL and Blob Input, bind-toggle arity, and legacy dataURL fallback was improved with force-download mime and base64 support
  • 2015 :: converted to amd/commonJS module with browser-friendly fallback
  • 2015 :: 4.1 added direct URL downloading via a single URL argument.
  • 2016 :: 4.2 added large dataURL support, a more semantic codebase, and hidden temp links
  • 2017 :: added support for empty dataURLs
  • 20XX :: ???? Considering Zip, Tar, and other multi-file outputs, Blob.prototype.download option, and more, stay tuned folks.