Skip to Content
ServicesStorage Service

Storage Service

The Storage Service provides a unified interface for file uploads, supporting multiple providers like Vercel Blob, Cloudinary, and AWS S3-compatible services (like Cloudflare R2). It abstracts the underlying implementation, allowing you to switch providers with simple configuration changes.


Supported Providers

  • Vercel Blob (Default)
  • Cloudinary
  • AWS S3 / Cloudflare R2

Configuration

Set the STORAGE_PROVIDER environment variable to choose your provider.

Vercel Blob (Default)

Great for Vercel deployments.

# .env STORAGE_PROVIDER=vercel BLOB_READ_WRITE_TOKEN=vercel_blob_rw_...

Cloudinary

Ideal for media optimization and transformation.

# .env STORAGE_PROVIDER=cloudinary CLOUDINARY_CLOUD_NAME=your-cloud-name CLOUDINARY_API_KEY=your-api-key CLOUDINARY_API_SECRET=your-api-secret CLOUDINARY_FOLDER=orbitus # Optional, defaults to 'orbitus'

AWS S3 / Cloudflare R2

Flexible object storage for any S3-compatible provider.

# .env STORAGE_PROVIDER=s3 # or 'aws', 'r2' AWS_ACCESS_KEY_ID=your-access-key AWS_SECRET_ACCESS_KEY=your-secret-key AWS_REGION=us-east-1 # or 'auto' for R2 AWS_BUCKET_NAME=your-bucket-name AWS_ENDPOINT=https://... # Optional for S3, required for R2

Usage

Basic Usage

Import storageService to interact with the configured provider.

import { storageService } from '@orbitusdev/core/services/storage'; // Upload a file const { url } = await storageService.upload('users/avatar.jpg', fileBlob, { access: 'public' }); // Delete a file await storageService.delete(url);

API Route Example (App Directory)

Implementation of a file upload endpoint using Next.js Route Handlers.

// app/api/upload/route.ts import { NextResponse } from 'next/server'; import { storageService } from '@orbitusdev/core/services/storage'; export async function POST(request: Request) { try { const formData = await request.formData(); const file = formData.get('file') as File; if (!file) { return NextResponse.json( { error: 'No file provided' }, { status: 400 } ); } // Generate a unique path/filename if needed const filename = `uploads/${Date.now()}-${file.name}`; const { url } = await storageService.upload(filename, file, { access: 'public' }); return NextResponse.json({ url }); } catch (error) { console.error('Upload error:', error); return NextResponse.json( { error: 'Upload failed' }, { status: 500 } ); } }

Server Action Example

Using Server Actions for handling form submissions with file uploads directly.

'use server'; import { storageService } from '@orbitusdev/core/services/storage'; export async function uploadAction(formData: FormData) { const file = formData.get('profileImage') as File; if (!file || file.size === 0) { throw new Error('Invalid file'); } const { url } = await storageService.upload( `profiles/${file.name}`, file, { access: 'public' } ); return { success: true, url }; }

Interface

The service adheres to the IStorageService interface.

export interface IStorageService { /** * Upload a file to the storage provider * @param path The destination path/filename * @param file The file or blob content * @param options Upload options (e.g., public/private access) */ upload( path: string, file: File | Blob, options?: { access?: 'public' | 'private' } ): Promise<{ url: string }>; /** * Delete a file from the storage provider * @param url The public URL of the file to delete */ delete(url: string): Promise<void>; }

Best Practices

  1. File Validation: Always validate file type (MIME type) and size before calling upload.
  2. Unique Filenames: Use timestamps or UUIDs in filenames to prevent overwriting existing files.
  3. Environment Security: Never expose your secret keys (API_SECRET, AWS_SECRET, etc.) in public variables (NEXT_PUBLIC_).
  4. Access Control: Use access: 'private' if the files shouldn’t be publicly accessible (note: not all providers support this simply).
  5. Error Handling: Wrap calls in try/catch blocks to handle network issues or provider rejections.

Last updated on