Skip to Content

Fastify Integration

This guide explains how to integrate FileZen with Fastify applications using the @filezen/js package. This package provides a ZenStorage class that simplifies file upload and management operations with comprehensive error handling and automatic multipart upload support.

Fastify offers several advantages over Express including better performance, native TypeScript support, modern plugin system, and built-in structured logging.

📁 Code Example: See the complete Fastify server example  for a working implementation with interactive test interface.

Installation

Install the FileZen JavaScript SDK:

Quick Start

1. Environment Configuration

Set your FileZen API key as an environment variable. This can be done in your local .env file during development or as a system environment variable in production.

.env
FILEZEN_API_KEY=your_api_key_here

The FileZen SDK automatically detects the FILEZEN_API_KEY environment variable for server-side operations, so no additional configuration is needed in your server setup. The keepUploads option defaults to false for server-side usage, so temporary uploads are automatically cleaned up.

2. Initialize ZenStorage

Create a ZenStorage instance with your configuration. The SDK will automatically detect the FILEZEN_API_KEY from your environment variables.

storage.js
import { ZenStorage } from '@filezen/js'; // Initialize storage with automatic environment variable detection const zenStorage = new ZenStorage({ apiKey: "your_api_key_here", // Optional: can use FILEZEN_API_KEY env var });

3. Upload Files

You can now use the ZenStorage instance to upload files with various methods.

upload_example.js
import fs from 'fs'; // Upload a single file from file path const fileBuffer = fs.readFileSync(filePath); const upload = await zenStorage.upload(fileBuffer, { name: 'my-file.jpg', mimeType: 'image/jpeg', }); if (upload.error) { console.error('Upload failed:', upload.error); } else { console.log('File uploaded:', upload.file.url); }

FileZen Functions

Single File Upload

Upload individual files with error handling.

single_upload.js
import fs from 'fs'; async function uploadSingleFile(filePath, filename, mimeType) { const fileBuffer = fs.readFileSync(filePath); const upload = await zenStorage.upload(fileBuffer, { name: filename, mimeType: mimeType, }); if (upload.error) { throw new Error(`Upload failed: ${upload.error.message}`); } return { url: upload.file.url, name: upload.file.name, size: upload.file.size, mimeType: upload.file.mimeType, }; }

Bulk Upload

Upload multiple files concurrently for better performance.

bulk_upload.js
async function uploadMultipleFiles(filesData) { const uploadItems = filesData.map(file => ({ source: file.buffer, options: { name: file.filename, mimeType: file.mimetype, }, })); const uploads = await zenStorage.bulkUpload(...uploadItems); // Check for any upload errors const failedUploads = uploads.filter(upload => upload.error); if (failedUploads.length > 0) { const failures = failedUploads.map(upload => ({ name: upload.name || 'unknown', error: upload.error?.message || 'Unknown error' })); throw new Error(`${failedUploads.length} uploads failed`); } return uploads.map(upload => ({ url: upload.file.url, name: upload.file.name, size: upload.file.size, mimeType: upload.file.mimeType, })); }

Upload from URL

Upload files directly from external URLs.

url_upload.js
async function uploadFromUrl(sourceUrl, fileName) { const upload = await zenStorage.uploadFromUrl(sourceUrl, { name: fileName || 'downloaded-file', }); if (upload.error) { throw new Error(`URL upload failed: ${upload.error.message}`); } return { url: upload.file.url, name: upload.file.name, size: upload.file.size, mimeType: upload.file.mimeType, }; }

Upload from Base64

Upload files from base64 encoded data.

base64_upload.js
async function uploadFromBase64(base64Data, fileName, mimeType) { const upload = await zenStorage.uploadFromBase64(base64Data, { name: fileName || 'base64-file', mimeType: mimeType, }); if (upload.error) { throw new Error(`Base64 upload failed: ${upload.error.message}`); } return { url: upload.file.url, name: upload.file.name, size: upload.file.size, mimeType: upload.file.mimeType, }; }

Manual Multipart Upload Control

For fine-grained control over multipart uploads, especially for large files or when you need to track progress:

multipart_upload.js
async function manualMultipartUpload(file, fileName, mimeType) { // Start multipart upload session const { id: sessionId } = await zenStorage.multipart.start({ fileName: fileName, mimeType: mimeType, totalSize: file.size, uploadMode: 'STREAMING', metadata: { type: 'manual_upload' } }); let uploadedSize = 0; const chunkSize = 5 * 1024 * 1024; // 5MB chunks // Upload file in chunks while (uploadedSize < file.size) { // Create a chunk from the current position const chunk = file.slice( uploadedSize, Math.min(file.size, uploadedSize + chunkSize) ); // Upload this specific chunk await zenStorage.multipart.uploadPart({ sessionId: sessionId, chunk: chunk }); // Update progress uploadedSize = Math.min(file.size, uploadedSize + chunkSize); console.log(`Uploaded ${uploadedSize}/${file.size} bytes`); } // Finalize the multipart upload const result = await zenStorage.multipart.finish({ sessionId: sessionId }); return result; }

Generate Signed URL

Generate secure signed URLs for direct uploads from client applications.

signed_url.js
function generateUploadUrl(fileKey, expirationTime = 3600) { const signedUrl = zenStorage.generateSignedUrl({ path: '/files/upload', fileKey: fileKey, expiresIn: expirationTime, // 1 hour by default }); return { signedUrl: signedUrl, expiresIn: expirationTime, }; }

Delete File

Delete files by their URL.

delete_file.js
async function deleteFile(fileUrl) { try { await zenStorage.deleteByUrl(fileUrl); return { success: true, message: 'File deleted successfully' }; } catch (error) { throw new Error(`Failed to delete file: ${error.message}`); } }

Complete Fastify Server Example

Here’s a complete Fastify server implementation with all FileZen endpoints. This example demonstrates how to integrate FileZen with Fastify’s plugin system, multipart handling, and built-in logging.

Why Fastify?

Fastify offers several advantages over Express for FileZen integration:

  • Performance: Significantly faster than Express with better throughput
  • TypeScript: Native TypeScript support with better type safety
  • Plugins: Modern plugin system instead of middleware
  • Validation: Built-in JSON schema validation
  • Logging: Built-in structured logging
  • Multipart Handling: Uses @fastify/multipart instead of multer
complete-server.js
import Fastify from 'fastify'; import { ZenStorage } from '@filezen/js'; const fastify = Fastify({ logger: true }); // Register plugins await fastify.register(import('@fastify/multipart'), { limits: { fileSize: 100 * 1024 * 1024, // 100MB limit }, }); await fastify.register(import('@fastify/cors')); await fastify.register(import('@fastify/static'), { root: './public', // Serve static files }); // Initialize FileZen storage const zenStorage = new ZenStorage(); // Health check fastify.get('/', async (request, reply) => { return { message: 'FileZen Fastify Server Running' }; }); // Single file upload fastify.post('/api/files/upload', async (request, reply) => { try { const data = await request.file(); if (!data) { return reply.status(400).send({ success: false, error: 'No file provided' }); } const fileBuffer = await data.toBuffer(); const upload = await zenStorage.upload(fileBuffer, { name: data.filename, mimeType: data.mimetype, }); if (upload.error) { return reply.status(400).send({ success: false, error: upload.error.message }); } return { success: true, file: { url: upload.file.url, name: upload.file.name, size: upload.file.size, mimeType: upload.file.mimeType, }, }; } catch (error) { fastify.log.error('Upload error:', error); return reply.status(500).send({ success: false, error: 'Internal server error' }); } }); // Bulk file upload fastify.post('/api/files/bulk-upload', async (request, reply) => { try { const files = await request.saveRequestFiles(); if (!files || files.length === 0) { return reply.status(400).send({ success: false, error: 'No files provided' }); } const uploadItems = files.map(file => ({ source: file.file, options: { name: file.filename, mimeType: file.mimetype, }, })); const uploads = await zenStorage.bulkUpload(...uploadItems); // Check for any upload errors const failedUploads = uploads.filter(upload => upload.error); if (failedUploads.length > 0) { const failures = failedUploads.map(upload => ({ name: upload.name || 'unknown', error: upload.error?.message || 'Unknown error' })); return reply.status(400).send({ error: 'Some uploads failed', message: `${failedUploads.length} out of ${uploads.length} uploads failed`, failures: failures }); } const results = uploads.map(upload => ({ url: upload.file.url, name: upload.file.name, size: upload.file.size, mimeType: upload.file.mimeType, })); return { success: true, files: results, }; } catch (error) { fastify.log.error('Bulk upload error:', error); return reply.status(500).send({ success: false, error: 'Internal server error' }); } }); // Upload from URL fastify.post('/api/files/upload-from-url', async (request, reply) => { try { const { url, name } = request.body; if (!url) { return reply.status(400).send({ success: false, error: 'URL is required' }); } const upload = await zenStorage.uploadFromUrl(url, { name: name || 'downloaded-file', }); if (upload.error) { return reply.status(400).send({ success: false, error: upload.error.message }); } return { success: true, file: { url: upload.file.url, name: upload.file.name, size: upload.file.size, mimeType: upload.file.mimeType, }, }; } catch (error) { fastify.log.error('URL upload error:', error); return reply.status(500).send({ success: false, error: 'Internal server error' }); } }); // Upload from Base64 fastify.post('/api/files/upload-from-base64', async (request, reply) => { try { const { base64Data, name, mimeType } = request.body; if (!base64Data) { return reply.status(400).send({ success: false, error: 'Base64 data is required' }); } const upload = await zenStorage.uploadFromBase64(base64Data, { name: name || 'base64-file', mimeType: mimeType, }); if (upload.error) { return reply.status(400).send({ success: false, error: upload.error.message }); } return { success: true, file: { url: upload.file.url, name: upload.file.name, size: upload.file.size, mimeType: upload.file.mimeType, }, }; } catch (error) { fastify.log.error('Base64 upload error:', error); return reply.status(500).send({ success: false, error: 'Internal server error' }); } }); // Generate signed URL fastify.post('/api/files/generate-signed-url', async (request, reply) => { try { const { fileKey, expiresIn = 3600 } = request.body; if (!fileKey) { return reply.status(400).send({ success: false, error: 'fileKey is required' }); } const signedUrl = zenStorage.generateSignedUrl({ path: '/files/upload', fileKey: fileKey, expiresIn: expiresIn, }); return { success: true, signedUrl: signedUrl, expiresIn: expiresIn, }; } catch (error) { fastify.log.error('Signed URL generation error:', error); return reply.status(500).send({ success: false, error: 'Internal server error' }); } }); // Delete file fastify.delete('/api/files/delete', async (request, reply) => { try { const { url } = request.body; if (!url) { return reply.status(400).send({ success: false, error: 'File URL is required' }); } await zenStorage.deleteByUrl(url); return { success: true, message: 'File deleted successfully', }; } catch (error) { fastify.log.error('Delete error:', error); return reply.status(500).send({ success: false, error: 'Internal server error' }); } }); // Start server const start = async () => { try { await fastify.listen({ port: 3002, host: '0.0.0.0' }); console.log('Server running on http://localhost:3002'); } catch (err) { fastify.log.error(err); process.exit(1); } }; start();
Last updated on
© 2026 FileZen. All rights reserved.