Eazip

EAZIP BLOG

Client-Side vs. Server-Side ZIP: Where Should the Archive Get Built?

The download-all architecture decision in one page: where the bytes flow, what each side's size ceiling really is, who pays the bandwidth, and the cases where each approach — or a managed third option — clearly wins.

Ryan··4 min readarchitecturezip

Every "download all as ZIP" feature answers one architectural question first: does the archive get built in the user's browser or on a server? Everything else — cost, size limits, reliability, how much code you own — follows from that choice. This page is the decision, made explicit.

The short answer

Client-side (browser)Server-side (yours)
Bytes flowStorage → browserStorage → server → browser
Bandwidth costOne storage egress per downloadStorage egress plus your server's, per download
Size ceilingBrowser memory; tab must stay openServer memory/timeouts; streaming raises but doesn't remove it
Resume / progressIn-page progress; archive lost on reloadNo Content-Length → no progress bar, no resume
Storage configBucket CORS requiredNone
Server codeA URL-signing endpoint onlyThe whole fetch-and-zip pipeline

If you remember one heuristic: client-side wins on infrastructure (there nearly isn't any), server-side wins on control — and both share a ceiling that a third option exists to remove.

Where the bytes flow — and who pays

Client-side, each file travels storage → browser: one pass of storage egress per download, nothing through your servers. Server-side adds your own machine to the path; on egress-charging storage (S3 at ~$0.09/GB) a 20 GB export downloaded three times is ~$5.40 before your server's own bandwidth. The exception is zero-egress storage like R2, where proxying is operationally costly but financially free — the egress-cost breakdown runs the numbers per provider.

The ceilings are different in kind

The browser's ceiling is memory and lifetime: libraries like JSZip hold the archive in memory, streaming ones stretch it, but a multi-gigabyte ZIP in a tab is gambling either way — and a reload kills the job at 95% with nothing to resume.

The server's ceiling is time and delivery: streaming keeps memory flat, but the response has no Content-Length, so the user gets no progress bar and no Range resume, gateways impose timeouts (API Gateway's ~30 s, Lambda's hard 15 min), and a dropped connection restarts from zero. Neither side fails gracefully; they just fail differently.

When client-side clearly wins

  • The files are already reachable from the browser — public URLs, or signed URLs your endpoint returns anyway.
  • Exports are human-scale: tens to hundreds of files, well under browser-memory territory.
  • You want zero new infrastructure: an MIT library like Eazip.js plus a signing endpoint is the entire build.
  • The user is present — it's a button, and in-page progress is a feature.

When server-side clearly wins

  • No user is present: scheduled bundles, email-me-my-data flows, webhook-driven exports.
  • The archive needs server-side inputs — generated files, database dumps, cross-bucket assembly.
  • CORS is off the table: a compliance bucket that will never allow browser origins.
  • Auth is complex enough that you want exactly one place touching storage.

The third option both sides escalate to

The shared ceiling — big archives, reliable delivery — is what a managed job removes: the server decides what goes in the archive (a URL list), and a service does the fetching, zipping, and delivery as an expiring link with real Range/resume. Client-side code escalates by changing one option (strategy: 'cloud' in Eazip.js); server-side code escalates by POSTing the list instead of streaming the bytes. Either way you keep your architecture and drop its ceiling — at the price of a vendor and metered volume beyond free tiers.

FAQ

Is client-side zipping safe for private files?

Yes, with the same discipline as any download: the browser only receives short-lived signed URLs minted by an endpoint that authorized the user. Credentials never reach the client.

Which is faster for the user?

For small exports, client-side — no server hop, and fetching starts immediately. For large exports, neither: both hit their ceilings, which is precisely when the managed path with a prepared, resumable download wins on experience.

Can I do both?

That's the common end state: browser-side for everyday exports, the same signed-URL list to a managed job past a size threshold. The integration decision guide maps the exact switch points.

Does server-side always mean writing ZIP code?

No — that's the distinction between server-side execution and server-side ownership. Owning it means archiver, ZIP64, retries, and delivery are your code; the managed path keeps execution server-side while the ZIP machinery is someone else's problem.