Zipper

Server-Side Usage

Use Zipper in Node.js, Next.js API routes, Express, and other server environments

Server-Side Benefits

  • Privacy: Files never touch the client browser
  • Performance: Server bandwidth is typically faster
  • Security: Protected URLs and authentication
  • Scale: Handle large files without browser memory limits

🚀 Live Server Demo

See a full working server-side implementation with Next.js API routes

View Full Demo App

Next.js API Route

Create a server-side endpoint that generates and streams ZIP files to clients

// app/api/download/route.ts
import { NextResponse } from 'next/server';
import { createZipFile } from '@diegoaltoworks/zipper';

export async function GET() {
  const files = [
    { url: 'https://example.com/file1.pdf', name: 'Document-1.pdf' },
    { url: 'https://example.com/file2.pdf', name: 'Document-2.pdf' },
    { url: 'https://example.com/file3.pdf', name: 'Document-3.pdf' },
  ];

  // Create ZIP file on the server
  const zipData = await createZipFile(files, {
    onProgress: (current, total) => {
      console.log(`Server: Downloaded ${current}/${total} files`);
    },
    onError: (error, file) => {
      console.error(`Failed to download ${file.name}:`, error);
    },
    continueOnError: true,
    timeout: 30000,
  });

  // Convert to Uint8Array for NextResponse
  const buffer = zipData instanceof Blob
    ? new Uint8Array(await zipData.arrayBuffer())
    : new Uint8Array(zipData);

  return new NextResponse(buffer, {
    headers: {
      'Content-Type': 'application/zip',
      'Content-Disposition': 'attachment; filename="files.zip"',
    },
  });
}

Express.js Endpoint

Use with Express or any Node.js HTTP server

// Express.js API endpoint
import express from 'express';
import { createZipFile } from '@diegoaltoworks/zipper';

const app = express();

app.get('/api/download', async (req, res) => {
  try {
    const files = [
      { url: 'https://example.com/file1.pdf', name: 'Document-1.pdf' },
      { url: 'https://example.com/file2.pdf', name: 'Document-2.pdf' },
    ];

    const zipData = await createZipFile(files, {
      onProgress: (current, total) => {
        console.log(`Downloaded ${current}/${total} files`);
      },
    });

    // In Node.js, zipData is a Buffer
    res.setHeader('Content-Type', 'application/zip');
    res.setHeader('Content-Disposition', 'attachment; filename="files.zip"');
    res.send(zipData);
  } catch (error) {
    console.error('Error creating ZIP:', error);
    res.status(500).send('Error creating ZIP file');
  }
});

Standalone Node.js Script

Create ZIP archives in scripts, cron jobs, or CLI tools

// Standalone Node.js script
import { createZipFile } from '@diegoaltoworks/zipper';
import fs from 'fs';

async function createArchive() {
  const files = [
    { url: 'https://example.com/report-q1.pdf', name: 'Q1-Report.pdf' },
    { url: 'https://example.com/report-q2.pdf', name: 'Q2-Report.pdf' },
    { url: 'https://example.com/report-q3.pdf', name: 'Q3-Report.pdf' },
    { url: 'https://example.com/report-q4.pdf', name: 'Q4-Report.pdf' },
  ];

  console.log('Creating ZIP archive...');

  const zipBuffer = await createZipFile(files, {
    onProgress: (current, total) => {
      console.log(`Progress: ${current}/${total} (${Math.round(current/total*100)}%)`);
    },
    onError: (error, file) => {
      console.error(`Failed: ${file.name}`, error.message);
    },
    continueOnError: true,
  });

  // Save to disk
  fs.writeFileSync('./archive.zip', zipBuffer);
  console.log('ZIP file saved to archive.zip');
}

createArchive();

Dynamic File Lists

Fetch files from database, S3, or any data source

// Next.js API route with dynamic file list from database
import { NextResponse } from 'next/server';
import { createZipFile } from '@diegoaltoworks/zipper';
import { db } from '@/lib/database';

export async function POST(request: Request) {
  const { userId } = await request.json();

  // Fetch user's documents from database
  const documents = await db.documents.findMany({
    where: { userId },
    select: { url: true, filename: true },
  });

  // Transform to zipper format
  const files = documents.map(doc => ({
    url: doc.url,
    name: doc.filename,
  }));

  // Create ZIP
  const zipData = await createZipFile(files, {
    onProgress: (current, total) => {
      console.log(`User ${userId}: ${current}/${total} files`);
    },
  });

  const buffer = zipData instanceof Blob
    ? new Uint8Array(await zipData.arrayBuffer())
    : new Uint8Array(zipData);

  return new NextResponse(buffer, {
    headers: {
      'Content-Type': 'application/zip',
      'Content-Disposition': `attachment; filename="user-${userId}-documents.zip"`,
    },
  });
}

🔑 Key Differences

Use createZipFile() instead of downloadZipFile()

Server-side uses createZipFile() which returns a Buffer/Blob. Client-side uses downloadZipFile() which triggers browser download.

Return type is Buffer in Node.js

In Node.js environment, the function returns a Buffer. In browser, it returns a Blob.

Set proper HTTP headers

Always set Content-Type to 'application/zip' and Content-Disposition for filename.

📦 Bulk Exports

Let users download all their documents, invoices, or reports as a single ZIP

🔒 Protected Content

Serve files from authenticated URLs without exposing them to the client

📊 Report Generation

Create archives of generated PDFs, CSVs, and other dynamic content

⚡ Background Jobs

Process large file collections in scheduled tasks or worker queues