Eazip
Guides

Download DigitalOcean Spaces Files as a ZIP

Presign DigitalOcean Spaces objects on the server, then package them into one browser-downloaded ZIP with Eazip.

DigitalOcean Spaces is S3-compatible, so the fastest way to let a user download a folder of Space objects as one archive is to presign each object URL on your server, then hand the list to Eazip in the browser. Eazip fetches each URL and streams the ZIP without ever seeing your Spaces access key.

Loading live demo…

Prepare presigned URLs on the server

Your backend endpoint should:

  1. authenticate the application user;
  2. authorize each requested object (verify the key belongs to that user's folder or project);
  3. create a short-lived presigned GET URL with the S3 SDK; and
  4. return only { url, filename } entries.

Spaces accepts the standard AWS SDK, so presigning uses the same client you would use for S3:

import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';

const spaces = new S3Client({
  endpoint: 'https://nyc3.digitaloceanspaces.com',
  region: 'us-east-1', // Spaces ignores this; the endpoint sets the datacenter
  forcePathStyle: false,
  credentials: {
    accessKeyId: process.env.SPACES_KEY!,
    secretAccessKey: process.env.SPACES_SECRET!,
  },
});

type SignedSource = {
  url: string;
  filename: string;
};

async function presignFolder(
  bucket: string,
  keys: string[],
): Promise<SignedSource[]> {
  return Promise.all(
    keys.map(async (key) => ({
      url: await getSignedUrl(
        spaces,
        new GetObjectCommand({ Bucket: bucket, Key: key }),
        { expiresIn: 300 },
      ),
      filename: key.split('/').pop() ?? key,
    })),
  );
}

Replace nyc3 with your Space's region. Keep forcePathStyle: false so requests use virtual-hosted-style URLs, which is what Spaces expects.

Configure Spaces CORS

A Local (browser) job fetches each presigned URL directly from the visitor's tab, so the Space must allow your application's origin. In the control panel, open Spaces Object Storage → your bucket → Settings → CORS Configurations and add a rule:

  • Origin: https://app.example.com (one wildcard subdomain is allowed, such as https://*.example.com)
  • Allowed Methods: GET
  • Allowed Headers: * or the specific headers your requests send

If the bucket sits behind the Spaces CDN, purge the CDN cache after changing CORS rules so edge servers serve the updated headers. Presigned URLs are not cached by the CDN, so serving them through the CDN edge endpoint adds latency without a benefit — fetch presigned URLs from the origin endpoint (<space>.<region>.digitaloceanspaces.com), and reserve the CDN edge endpoint (<space>.<region>.cdn.digitaloceanspaces.com) for public, non-signed assets.

Create the ZIP in the browser

import { createZip } from '@eazip/core';

type SignedSource = {
  url: string;
  filename: string;
};

const response = await fetch('/api/exports/folder-42/files', {
  credentials: 'include',
});

if (!response.ok) {
  throw new Error('Could not prepare export files');
}

const files = (await response.json()) as SignedSource[];
const result = await createZip({
  files,
  zipName: 'project-files.zip',
});

result.download();

createZip() resolves once every reachable file has been fetched and zipped; result.download() then starts the browser download. Each presigned URL must stay valid until Eazip fetches it, so set expiresIn generously for larger folders — a slow connection can take longer than the 300 seconds used above.

When to use Eazip Cloud

Local works well for a folder a person picks in the UI. Move to Eazip Cloud when:

  • the folder is multi-gigabyte or holds thousands of objects;
  • the job should survive a page reload;
  • Spaces CORS cannot be opened for the requesting origin; or
  • archive bytes should not sit in browser tab memory.

Cloud fetches the same presigned URLs from Eazip's servers instead of the browser:

const result = await createZip({
  strategy: 'cloud',
  publicKey: 'pk_ez_...',
  files,
  zipName: 'project-files.zip',
});

result.downloadAll();

Add *.digitaloceanspaces.com (or your Space's exact hostname) to the Public App's allowed source hosts, and keep the presigned URL lifetime long enough for Cloud to start and finish reading the folder.

Limits and when Eazip is not needed

Spaces subscriptions include 1 TiB of outbound transfer shared across your buckets, so archiving does not add a separate egress fee inside that allowance — normal Spaces bandwidth pricing still applies past it. If a single object is all a user needs, send them the presigned URL directly and skip archiving altogether. If your users only ever need the same fixed set of files, a scheduled job that writes one ZIP object back into the Space and returns a presigned URL for it may be simpler than zipping on every request.

FAQ

How do I download a whole DigitalOcean Spaces folder as one ZIP?

List the objects under the folder's key prefix, presign each one on your server, and pass the { url, filename } list to createZip() in the browser. See Prepare presigned URLs on the server.

Can I generate a presigned URL for a Spaces folder instead of each file?

No. S3-compatible presigned URLs authorize exactly one object. Presign each key in the folder and let Eazip combine the results into one archive.

Why do my Spaces presigned URLs fail with a CORS error in the browser?

The bucket's CORS configuration does not allow your page's origin, or the presigned URL expired before the browser fetched it. Add the origin under Settings → CORS Configurations and confirm expiresIn covers how long the export can take. See Configure Spaces CORS.

Does zipping through the Spaces CDN save bandwidth?

No. Presigned URLs bypass the CDN cache on every request, so fetching them through the CDN edge endpoint adds latency without reducing origin reads. Use the origin endpoint for presigned downloads.

When should I use Eazip Cloud instead of zipping in the browser?

When the folder is too large, too numerous, or too CORS-restricted for a browser tab to handle reliably. See When to use Eazip Cloud.

Continue with Create a ZIP from remote URLs, Input types, or Eazip Cloud.