PackagesStorage Providers
@prood/storage-s3
S3-compatible storage provider for AWS S3, Cloudflare R2, and MinIO.
@prood/storage-s3 implements the StorageProvider interface for any S3-compatible object storage — AWS S3, Cloudflare R2, MinIO, or other compatible services.
Installation
pnpm add @prood/storage-s3Selected when STORAGE_PROVIDER=s3.
Configuration
| Variable | Required | Description |
|---|---|---|
S3_ENDPOINT | Yes | S3-compatible endpoint URL |
S3_REGION | No | Region (default auto for R2) |
S3_BUCKET | Yes | Bucket name |
S3_ACCESS_KEY_ID | Yes | Access key |
S3_SECRET_ACCESS_KEY | Yes | Secret key |
S3_PUBLIC_URL | No | Public CDN URL prefix for uploaded files |
Cloudflare R2 example
STORAGE_PROVIDER=s3
S3_ENDPOINT=https://abc123.r2.cloudflarestorage.com
S3_REGION=auto
S3_BUCKET=prood-assets
S3_ACCESS_KEY_ID=your_access_key
S3_SECRET_ACCESS_KEY=your_secret_key
S3_PUBLIC_URL=https://assets.example.comAWS S3 example
STORAGE_PROVIDER=s3
S3_ENDPOINT=https://s3.eu-west-1.amazonaws.com
S3_REGION=eu-west-1
S3_BUCKET=prood-assets
S3_ACCESS_KEY_ID=AKIA...
S3_SECRET_ACCESS_KEY=...
S3_PUBLIC_URL=https://prood-assets.s3.eu-west-1.amazonaws.comUsage
Via @prood/commerce (preferred):
import { uploadForTenant } from '@prood/commerce'
const result = await uploadForTenant(orgId, {
file: buffer,
filename: 'product-image.jpg',
contentType: 'image/jpeg',
directory: `products/${productId}`,
})Direct usage:
import { S3StorageProvider } from '@prood/storage-s3'
const storage = new S3StorageProvider({
endpoint: process.env.S3_ENDPOINT!,
region: process.env.S3_REGION ?? 'auto',
bucket: process.env.S3_BUCKET!,
accessKeyId: process.env.S3_ACCESS_KEY_ID!,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
publicUrl: process.env.S3_PUBLIC_URL,
})Tenant namespacing
Same as Vercel Blob — all keys prefixed with org/{orgId}/:
org/org_demo/products/prod_abc/image.jpgAlways upload via uploadForTenant() to ensure proper namespacing.