Prood
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-s3

Selected when STORAGE_PROVIDER=s3.

Configuration

VariableRequiredDescription
S3_ENDPOINTYesS3-compatible endpoint URL
S3_REGIONNoRegion (default auto for R2)
S3_BUCKETYesBucket name
S3_ACCESS_KEY_IDYesAccess key
S3_SECRET_ACCESS_KEYYesSecret key
S3_PUBLIC_URLNoPublic 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.com

AWS 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.com

Usage

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.jpg

Always upload via uploadForTenant() to ensure proper namespacing.

On this page