Eazip
Eazip.jsPricingSign inStart free
Guides

Cut the Egress Cost of ZIP Exports

The bandwidth math of a "download all" feature — why proxying files multiplies egress, what each storage provider charges, and the prepare-once pattern that caps the cost at one pass.

Bandwidth is the invisible line item of every "download all as ZIP" feature. The files are already paid for in storage; what surprises teams is that serving them can cost more than storing them — especially when the architecture quietly pays egress more than once per file.

Where the money leaks

Count how many times a byte leaves a paid network boundary:

  • Proxy-per-download (the classic server-side ZIP): bucket → your server → user, on every download. A 20 GB export from S3 downloaded three times moves 60 GB out of AWS: ~$5.40, forever coupled to how often users click.
  • Browser-side ZIP with signed URLs: bucket → user directly. One pass per download — better, but still per-download, and re-fetching every object on a retry.
  • Prepare-once (stored job): bucket → archive, once. Repeat downloads serve the prepared archive; the bucket is never read again for that export.

The pattern, not the provider, is usually the biggest lever: going from proxy-per-download to prepare-once divides source egress by the number of downloads.

What providers actually charge

Standard published rates at the time of writing (verify against current pricing pages — regions and tiers vary):

SourceEgress rateNotes
AWS S3~$0.09/GBAfter 100 GB/month free across the account (US regions, first 10 TB tier)
Cloudflare R2$0Read operations bill per-request (cents/million); bytes are free
Supabase Storage$0.09/GB over quotaUnified project quota: 5 GB free plan, 250 GB included on Pro
Google Cloud Storage~$0.12/GBRegion-dependent
Backblaze B2$0.01/GBFree up to 3× stored data; free via Cloudflare's network

Two readings of that table:

  1. If your exports live on S3 or GCS, the pattern matters most — you can't change the rate, so pay it once per export instead of once per download.
  2. If you control where new data lands, R2 (or B2) changes the game — a ZIP pipeline from R2 through Eazip has no per-GB bandwidth charge on either leg (Eazip adds no outbound-bandwidth fee: zero-egress exports).

The prepare-once pattern

One job per export; the default stored mode fetches each source a single time while preparing the archive, and every subsequent download serves the prepared copy:

await fetch('https://api.eazip.io/jobs', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.EAZIP_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    files, // presigned URLs — see the platform guides
    zip_filename: 'export.zip',
    expires_in: 7 * 86400,
  }),
});

Cost shape: (source egress × archive size × 1) + Eazip plan quota (stored GB-days). The per-platform signing code and each platform's numbers: S3, R2, Supabase Storage.

Note the honest counterpoint: stream mode inverts this. Streamed jobs re-fetch sources per download — the right choice for downloaded-once archives (no retention quota), the wrong one for a gallery grabbed by the whole family. Stream or stored is the decision page.

Three checks before you optimize anything

  1. Are you proxying? If export bytes pass through your app servers, fixing that beats every other change — presign and let the fetcher go to the bucket directly.
  2. Are repeat downloads re-reading the bucket? Logs will show the same objects fetched for the same export. That is the prepare-once gap.
  3. Is a CDN actually helping? Signed URLs with unique query strings defeat caching, and most one-off exports are never fetched twice from the same edge anyway — CDNs solve popular-content bandwidth, not export bandwidth.

FAQ

Does moving the ZIP work to a service eliminate S3 egress?

No — someone still reads each object from S3 once, and AWS bills that pass. What the prepare-once pattern eliminates is every pass after the first. Zero source egress exists only where the source itself charges zero (R2, or B2 within its free allowances).

Is browser-side zipping cheaper than a managed job?

For a single download of a small export, they're equivalent (one pass either way) and the browser path has no service involved. The managed job wins on repeat downloads — the browser re-fetches everything, the stored archive doesn't.

We're on S3 — should we migrate to R2 for this?

Not for exports alone unless they dominate your bandwidth bill. But new write paths that exist mainly to be re-downloaded (deliverables, galleries, report bundles) are natural R2 candidates: same S3 API, $0.09/GB → $0.