Download All Firebase Storage Files as a ZIP
List a Cloud Storage for Firebase folder, turn the files into a ZIP in the browser, and scale past tab limits with Eazip Cloud.
Firebase Storage has no built-in ZIP export. To let a user download a whole folder as one file, list the objects, get a URL for each one, and pass those URLs to Eazip. You can do this entirely with the client Web SDK, or generate signed URLs on a server for private files.
Loading live demo…
Client-only: list and zip with the Web SDK
If your Security Rules already allow the signed-in user to read a folder, you
do not need a server at all. listAll() returns every item under a path, and
getDownloadURL() returns a browser-fetchable URL with an access token
embedded:
import { getStorage, ref, listAll, getDownloadURL } from 'firebase/storage';
import { createZip } from '@eazip/core';
const storage = getStorage();
const folderRef = ref(storage, `exports/${userId}`);
const { items } = await listAll(folderRef);
const files = await Promise.all(
items.map(async (itemRef) => ({
url: await getDownloadURL(itemRef),
filename: itemRef.name,
})),
);
const result = await createZip({
files,
zipName: 'export.zip',
});
result.download();listAll() buffers the whole listing in memory, so it fits a single folder of
files rather than a bucket-wide crawl. For a deeply nested path, call
listAll() on each prefixes entry to walk subfolders, and build a
filename that keeps the folder structure, for example
${folderPath}/${itemRef.name}.
Firebase Storage download URLs point at
firebasestorage.googleapis.com, which returns CORS headers that allow a
browser fetch(), so this works as a Local job with no extra configuration.
Server-signed URLs with the Admin SDK
Use a server when files are private, when only an authorized backend should
decide which objects a user may export, or when you want a single endpoint
instead of relying on Security Rules for every read. The Admin SDK's bucket
is a @google-cloud/storage bucket, so you can list by prefix and sign each
object directly:
// server
import { getStorage } from 'firebase-admin/storage';
export async function getExportFiles(uid: string) {
const bucket = getStorage().bucket();
const [objects] = await bucket.getFiles({ prefix: `exports/${uid}/` });
return Promise.all(
objects.map(async (file) => {
const [url] = await file.getSignedUrl({
action: 'read',
expires: Date.now() + 15 * 60 * 1000,
});
return { url, filename: file.name.split('/').pop()! };
}),
);
}// browser
import { createZip } from '@eazip/core';
const response = await fetch('/api/exports/files', { credentials: 'include' });
const files = (await response.json()) as { url: string; filename: string }[];
const result = await createZip({
files,
zipName: 'export.zip',
});
result.download();Never send a Firebase Admin service account key or an unscoped bucket
credential to the browser. The endpoint should authenticate the request,
authorize the specific prefix or object list, and return only
{ url, filename } entries. Signed GCS URLs allow browser GETs by default;
if you serve objects through a custom domain in front of the bucket, confirm
that domain also returns CORS headers, or configure them with
gcloud storage buckets update --cors-file.
When to use Eazip Cloud
Local jobs cover most exports, but switch to strategy: 'cloud' when:
- the folder has thousands of files or the archive would be multi-gigabyte;
- signed URLs may expire before a slow connection finishes fetching them all;
- the export should keep running if the user closes the tab or reloads; or
- you would rather not hold every object's bytes in browser tab memory.
const result = await createZip({
strategy: 'cloud',
publicKey: 'pk_ez_...',
files,
zipName: 'export.zip',
});
result.downloadAll();Add firebasestorage.googleapis.com (or your custom domain) to the Public
App's allowed source hosts, and give signed URLs enough lifetime for Eazip
Cloud to start and finish reading them. Eazip Cloud usage is metered, and
Cloud Storage still bills its own bandwidth for the source fetches — "zero
egress" here means Eazip does not add a separate outbound-bandwidth fee on
top of that.
Limits and alternatives
For a handful of files, looping getDownloadURL() and triggering one
download per file is simpler than a ZIP and needs no extra dependency. A
Cloud Function that zips objects server-side works for small exports, but you
own its memory and timeout limits, and every added file grows both; Eazip
Cloud is built for that job instead. On the Spark plan, watch Cloud Storage's
free bandwidth quota — a folder-wide export can consume it quickly, and
Blaze bills download bandwidth per GB regardless of whether Eazip or a
Cloud Function reads the objects.
FAQ
Can I download a whole folder from Firebase Storage?
Yes. List the folder with listAll() (client) or bucket.getFiles({ prefix }) (server), collect a URL per file, and pass the list to createZip().
There is no folder-download button in the Firebase console or client SDK.
Does Firebase have a built-in ZIP export?
No. Cloud Storage for Firebase stores and serves individual objects; zipping is left to your application, a Cloud Function, or a service like Eazip.
Do I need a backend to zip Firebase Storage files?
Not if your Security Rules already allow the signed-in user to read the
folder — listAll() and getDownloadURL() from the Web SDK are enough. Add
a server step only for private files or centralized authorization.
Why do some Firebase Storage downloads fail with a CORS error?
Standard firebasestorage.googleapis.com download URLs already allow
browser GETs. A CORS failure usually means you fetched a custom-domain or
direct storage.googleapis.com URL that needs its own CORS configuration via
gcloud storage buckets update --cors-file.
How many files can I zip from Firebase Storage in the browser?
There is no hard limit, but tab memory, listing size, and signed URL lifetime all shrink as the folder grows. Move to Eazip Cloud once a folder runs into the thousands of files or multiple gigabytes.
Continue with When to use Eazip Cloud, Input types, and Create a ZIP from remote URLs.
Download Cloudflare R2 Objects as a ZIP
Presign R2 objects on the server, then zip them in the browser with Eazip — no storage credentials client-side and no R2 egress fees.
Download Google Cloud Storage Files as a ZIP
List a bucket prefix, sign V4 read URLs, and package the objects into one ZIP with @eazip/core in the browser.