Eazip
Eazip.jsPricingSign inStart free
Guides

Fix AWS Lambda Timing Out While Zipping Files

Why Lambda ZIP jobs die at 15 minutes (or 29 seconds), the quick fixes — streaming, memory, direct invocation — and the structural fix of moving the fetch-and-zip work out of the function.

The symptom: your Lambda builds ZIP archives from S3 objects, it worked in testing, and now real exports fail — the function stops at its timeout, the API Gateway request dies long before that, or memory blows up somewhere past a few hundred files.

This page is the diagnosis order, the quick fixes, and the honest boundary where Lambda stops being the right home for this job.

Which wall are you hitting?

  • 29 seconds, gateway 504. API Gateway cuts the integration at its ~30-second default long before Lambda's own limit. Any synchronous "request → zip → response" design hits this first.
  • 15 minutes, function timeout. Lambda's hard execution cap. No configuration raises it. A ZIP job's duration scales with total bytes fetched, so every archive size has a wall-clock ceiling somewhere.
  • Out of memory / out of disk. Building the archive in memory (JSZip and friends) caps you at the function's memory (up to 10 GB); building on disk caps at /tmp (up to 10 GB). Streaming avoids both — until the 15-minute wall.

Quick fixes, in order

  1. Get out from behind API Gateway. Make the export asynchronous: respond immediately with a job ID, run the work via direct async invocation (or SQS), and deliver a link when done. This removes the 29-second wall entirely.
  2. Stream instead of buffering. Pipe S3 GetObject streams through archiver into an S3 multipart upload — memory stays flat and /tmp is untouched. (The Node pattern is in the S3 roundup.)
  3. Raise memory anyway. Lambda allocates CPU proportionally to memory, so a 2–4 GB function zips measurably faster than a 512 MB one — sometimes that's the difference between finishing at 12 minutes and dying at 15.
  4. Bound the input. Cap objects per archive and split large exports into several invocations producing several ZIPs.

These are real fixes, and for exports that reliably finish in a few minutes, they are the end of the story.

The structural fix

If exports keep growing, you are optimizing toward a hard wall: 15 minutes, times however fast S3 will feed one function. The structural fix is to stop doing the fetch-and-zip inside Lambda at all — the function's job shrinks to deciding what goes in the archive:

// Inside the Lambda: list, presign, hand off — seconds of work,
// regardless of archive size.
const files = await listPrefixAsSignedUrls(BUCKET, prefix);

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, zip_filename: 'export.zip' }),
});

The function now runs for seconds, whatever the export size; the archive builds outside any function wall clock (output scales to 500 GB per job), and the result is an expiring download link with Range/resume — something a Lambda response can't offer anyway. Flow details: Create a ZIP from URLs with One API Call; S3 specifics (presign lifetimes with role credentials — the other classic Lambda gotcha): Zip S3 Files via API.

One caution on that gotcha, because it bites exactly this setup: presigned URLs signed with the Lambda role's session credentials die when the session expires, regardless of expiresIn. Sign with IAM user credentials if the job may start later than a few minutes after the function returns.

FAQ

Can I just ask AWS to raise the 15-minute limit?

No — it's a hard limit. Architectures change; the ceiling doesn't.

Is Step Functions a fix?

It orchestrates around the limit (chunked ZIPs across invocations, retries) but each step still lives inside 15 minutes, and you now own a distributed ZIP pipeline. Compare that build honestly: DIY Lambda ZIP vs. a managed service.

My exports are small — should I still move them out?

No. A streaming Lambda that finishes in two minutes is a fine design. Move the work when growth, reliability, or resumable delivery start costing you engineering time.

Does Lambda response streaming solve this?

It removes response-size buffering for synchronous downloads, but the 15-minute execution cap and the fragility of long-lived client connections remain. It helps mid-sized synchronous exports; it doesn't change the ceiling.