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.
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.
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.
// 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.
// downloadjs: Triggers download for ready data
download(blob, "report.pdf", "application/pdf");
file-saver also expects a complete Blob.
// file-saver: Triggers save dialog for Blob
saveAs(blob, "report.pdf");
streamsaver handles data as it arrives.
// streamsaver: Writes chunks directly to disk
const stream = streamsaver.createWriteStream("report.pdf");
const writer = stream.getWriter();
writer.write(chunk);
Memory management is critical for large files. Loading everything at once can crash the tab.
blob-stream holds the whole file in memory.
// 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.
// downloadjs: No memory optimization
download(largeBlob, "big-file.zip", "application/zip");
file-saver also relies on the input Blob.
// file-saver: No memory optimization
saveAs(largeBlob, "big-file.zip");
streamsaver avoids memory buildup.
// streamsaver: Constant memory usage
const stream = streamsaver.createWriteStream("big-file.zip");
// Write chunks as they are created, not all at once
Developer experience varies from single functions to stream piping.
blob-stream requires piping logic.
// blob-stream: Requires pipe setup
var stream = blobStream();
doc.pipe(stream);
downloadjs is a single function call.
// downloadjs: One function call
download(data, "file.txt", "text/plain");
file-saver is also a single function call.
// file-saver: One function call
saveAs(blob, "file.txt");
streamsaver requires stream writer setup.
// streamsaver: Requires writer setup
const stream = streamsaver.createWriteStream("file.txt");
const writer = stream.getWriter();
Compatibility depends on whether you use Blobs or Service Workers.
blob-stream works wherever Blobs work.
// blob-stream: Broad Blob support
var stream = blobStream();
// Works in most modern browsers
downloadjs uses basic link tricks.
// downloadjs: Broad support
download(data, "file.txt");
// Handles older browser quirks internally
file-saver handles browser quirks for Blobs.
// file-saver: Handles browser quirks
saveAs(blob, "file.txt");
// Includes polyfills for older browsers
streamsaver needs Service Workers.
// streamsaver: Requires Service Workers
const stream = streamsaver.createWriteStream("file.txt");
// Fails if Service Workers are not supported
| Feature | blob-stream | downloadjs | file-saver | streamsaver |
|---|---|---|---|---|
| Data Type | Stream to Blob | Data/Blob | Blob | Stream |
| Memory | High (Full Blob) | High (Full Blob) | High (Full Blob) | Low (Chunked) |
| API Style | Pipe Events | Function Call | Function Call | Stream Writer |
| Best For | PDF Generation | Simple Downloads | Standard Saves | Large Files |
| Browser | Broad | Broad | Broad | Modern Only |
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.
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.
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.
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.
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.
========
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.
npm install downloadjs
bower install downloadjs
require("downloadjs")(data, strFileName, strMimeType);
download function via <script> includedownload(data, strFileName, strMimeType);
require(['path/to/file'], function(download) {
download(data, strFileName, strMimeType);
});
download("hello world", "dlText.txt", "text/plain");
download("data:text/plain,hello%20world", "dlDataUrlText.txt", "text/plain");
download(new Blob(["hello world"]), "dlTextBlob.txt", "text/plain");
download("/robots.txt");
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" );
download(document.documentElement.outerHTML, "dlHTML.html", "text/html");
download(new Blob(["hello world".bold()]), "dlHtmlBlob.html", "text/html");
(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")
});
download("/diff6.png");
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();
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:
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...