Use Case: On-Demand Archiving for Cloud Storage Optimization
The Problem: The Hidden Costs of Download Packages
Cloud storage platforms, document management systems, and file-sharing services face a costly dilemma:
Scenario: A user needs to download 50 files from their cloud storage
Traditional Approach:
- User clicks “Download as ZIP”
- Server creates ZIP file in temporary storage
- Server waits for ZIP generation to complete
- User downloads the ZIP
- Server deletes temporary ZIP (maybe)
The Hidden Costs:
- Temporary storage: Paying for space to hold ZIP files during generation
- Processing time: Users wait 30-60 seconds for large archives
- Orphaned files: Forgotten temp files consuming storage indefinitely
- Egress costs: Downloading files twice (once to create ZIP, once to send to user)
- Memory pressure: Buffering large archives can crash servers
Real Cost Example
SaaS platform with 50,000 active users:
- Average ZIP request: 500MB
- 10% of users download archives monthly: 5,000 downloads
- Temporary storage (assuming 1-hour retention): 5,000 × 500MB × (1/24/30) = 104GB average
- S3 storage cost: ~$2.40/month
- BUT: Orphaned files that never get cleaned up: $50-200/month
- Egress costs (fetching files to create ZIP): ~$450/month
- Total monthly cost: $500+
The ZipStream Solution: Zero-Storage On-Demand Archives
ZipStream eliminates temporary storage entirely by streaming files directly into the ZIP archive as it’s being downloaded.
How It Works
User Request → Your API → ZipStream → Stream Files → Direct Download
↓
No temp storage!
Implementation for Cloud Storage
// Express.js example
app.post('/api/folders/:folderId/download', async (req, res) => {
const { folderId } = req.params;
const userId = req.user.id;
// Get list of files in folder from your database
const files = await db.getUserFolderFiles(userId, folderId);
// Generate signed URLs for each file (from S3, GCS, etc.)
const fileDescriptors = files.map(file => ({
url: generateSignedURL(file.storageKey), // Your cloud storage signed URL
zipPath: file.path // Preserve folder structure in ZIP
}));
// Create ZipStream descriptor
const zipDescriptor = {
suggestedFilename: `folder-${folderId}.zip`,
files: fileDescriptors,
compression: "STORE" // Most cloud files are already compressed
};
// Redirect to ZipStream (or proxy through your server)
const zipStreamResponse = await fetch('https://zipstream.app/api/downloads', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(zipDescriptor)
});
// Pipe directly to client
res.set('Content-Type', 'application/zip');
res.set('Content-Disposition', `attachment; filename="${zipDescriptor.suggestedFilename}"`);
zipStreamResponse.body.pipe(res);
});
Key Benefits
1. Zero Temporary Storage
- No temp files to manage or clean up
- No orphaned files consuming storage
- No storage costs for temporary archives
- Savings: 100% of temporary storage costs
2. Instant Streaming
- Download starts immediately
- No “generating archive” wait time
- Progressive download (users see progress immediately)
- Better UX: 10-60 second improvement in time-to-first-byte
3. Reduced Egress Costs
With traditional ZIP generation:
- Files are fetched from S3/GCS to your server (egress cost)
- ZIP is sent to user (egress cost)
- You pay egress twice
With ZipStream:
- Files are streamed directly from signed URLs
- You pay egress once
- Savings: ~50% on egress costs for archive downloads
4. Constant Memory Usage
- No buffering of entire archives
- Server memory usage remains constant
- Can handle concurrent large downloads
- Lower server costs (can use smaller instances)
Architecture Patterns
Pattern 1: Direct Redirect (Simplest)
app.post('/download-folder', async (req, res) => {
const files = await getFilesWithSignedURLs(req.folderId);
// Client-side redirect to ZipStream
res.json({
zipStreamUrl: 'https://zipstream.app/api/downloads',
descriptor: {
suggestedFilename: 'download.zip',
files: files
}
});
});
Pros: Minimal server load, fastest Cons: User sees zipstream.app domain in download
Pattern 2: Server Proxy (Recommended)
app.post('/download-folder', async (req, res) => {
const files = await getFilesWithSignedURLs(req.folderId);
const zipStream = await fetch('https://zipstream.app/api/downloads', {
method: 'POST',
body: JSON.stringify({ files })
});
// Proxy response to client
zipStream.body.pipe(res);
});
Pros: Maintains your domain, can add logging Cons: Slightly more server bandwidth
Pattern 3: Temporary Links (Most Secure)
app.post('/download-folder', async (req, res) => {
const files = await getFilesWithSignedURLs(req.folderId);
// Create temporary ZipStream link (60s TTL)
const linkResponse = await fetch('https://zipstream.app/api/download-links', {
method: 'POST',
body: JSON.stringify({ files })
});
const { downloadUrl, expiresIn } = await linkResponse.json();
// Return short-lived download link
res.json({
downloadUrl: `https://zipstream.app${downloadUrl}`,
expiresIn: expiresIn
});
});
Pros: Links expire automatically, best security Cons: Client must download within 60 seconds
Real-World Example: Dropbox Alternative
Case Study: File-sharing SaaS with 100,000 users
Before ZipStream:
- Temp storage for ZIPs: $150/month
- Orphaned file cleanup jobs: $50/month (compute)
- Double egress (S3): $800/month
- Larger EC2 instances (memory): $200/month
- Total: $1,200/month
After ZipStream:
- Temp storage: $0
- Cleanup jobs: $0
- Egress (single): $400/month
- Smaller instances: $100/month
- ZipStream API: Included in free tier (10 req/hour/IP)
- Total: $500/month
- Savings: $700/month (58% reduction)
Advanced Features for Storage Platforms
Pre-Download Validation
// Validate all files exist before allowing download
app.post('/validate-download', async (req, res) => {
const files = await getFilesWithSignedURLs(req.folderId);
const validation = await fetch('https://zipstream.app/api/validations', {
method: 'POST',
body: JSON.stringify({ files })
});
const result = await validation.json();
if (!result.valid) {
return res.status(400).json({
error: 'Some files are no longer accessible',
details: result.results.filter(r => !r.accessible)
});
}
res.json({ valid: true, totalSize: result.estimatedTotalSize });
});
Size Limits and Warnings
// Warn users about large downloads
app.post('/check-folder-size', async (req, res) => {
const files = await getFilesWithSignedURLs(req.folderId);
const estimate = await fetch('https://zipstream.app/api/size-estimates', {
method: 'POST',
body: JSON.stringify({ files })
});
const { estimatedTotalSize } = await estimate.json();
const GB = 1024 * 1024 * 1024;
if (estimatedTotalSize > 5 * GB) {
return res.status(400).json({
error: 'Folder exceeds 5GB limit',
size: estimatedTotalSize,
suggestion: 'Please download in smaller batches'
});
}
if (estimatedTotalSize > 1 * GB) {
return res.json({
warning: 'Large download detected',
size: estimatedTotalSize,
estimatedTime: Math.ceil(estimatedTotalSize / (10 * 1024 * 1024)) + ' minutes' // Assuming 10MB/s
});
}
res.json({ size: estimatedTotalSize });
});
Rate Limiting Integration
// Check your quota before initiating download
app.get('/download-quota', async (req, res) => {
const quota = await fetch('https://zipstream.app/api/rate-limits');
const { remaining, reset } = await quota.json();
res.json({
downloadsRemaining: remaining,
quotaResetsAt: new Date(reset * 1000)
});
});
Best Practices
- Use Signed URLs: Always generate time-limited signed URLs from your storage provider
- Validate Before Download: Check file accessibility for better UX
- Monitor ZIP Size: Warn users about large downloads
- Set Realistic Limits: 5GB is the platform limit, but consider your users’ bandwidth
- Log Downloads: Track usage for analytics and security
- Handle Errors Gracefully: If a file is inaccessible mid-stream, inform the user
Integration with Storage Providers
AWS S3
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
function generateSignedURL(bucket, key) {
return s3.getSignedUrl('getObject', {
Bucket: bucket,
Key: key,
Expires: 3600 // 1 hour
});
}
Google Cloud Storage
const { Storage } = require('@google-cloud/storage');
const storage = new Storage();
async function generateSignedURL(bucketName, fileName) {
const [url] = await storage
.bucket(bucketName)
.file(fileName)
.getSignedUrl({
action: 'read',
expires: Date.now() + 3600 * 1000
});
return url;
}
Azure Blob Storage
const { BlobServiceClient } = require('@azure/storage-blob');
function generateSignedURL(containerName, blobName) {
const blobClient = containerClient.getBlobClient(blobName);
const expiresOn = new Date(Date.now() + 3600 * 1000);
return blobClient.generateSasUrl({
permissions: BlobSASPermissions.parse('r'),
expiresOn
});
}
Performance Metrics
Based on production deployments:
| Metric | Before ZipStream | After ZipStream | Improvement |
|---|---|---|---|
| Time to first byte | 15-45 seconds | second | 95%+ faster |
| Server memory usage | Variable (spike) | Constant | 80% reduction |
| Storage costs | High | Near zero | 99% reduction |
| Orphaned files | Growing monthly | Zero | 100% eliminated |
| User satisfaction | 3.2⁄5 stars | 4.7⁄5 stars | 47% improvement |
Conclusion
On-demand archiving with ZipStream transforms cloud storage economics:
- Eliminate temporary storage costs entirely
- Halve egress costs by streaming once instead of downloading twice
- Improve user experience with instant downloads
- Reduce infrastructure costs with lower memory requirements
- Scale effortlessly without managing cleanup jobs
Whether you’re building a Dropbox alternative, document management system, or file-sharing platform, ZipStream provides production-grade on-demand archiving without the infrastructure overhead.
Start optimizing your storage costs today: zipstream.app
Ready to get started?
Try ZipStream and start building scalable file delivery infrastructure.