Cloudflare R2 Provider
Cost-effective storage with zero egress fees.
Installation
pnpm add @fluxmedia/core @fluxmedia/r2 @aws-sdk/client-s3 @aws-sdk/lib-storageR2 uses the S3-compatible API, so it requires @aws-sdk/client-s3.
Configuration
import { MediaUploader } from '@fluxmedia/core';
import { R2Provider } from '@fluxmedia/r2';
const uploader = new MediaUploader(
new R2Provider({
accountId: 'your-cloudflare-account-id',
bucket: 'my-bucket',
accessKeyId: 'your-r2-access-key',
secretAccessKey: 'your-r2-secret-key',
publicUrl: 'https://cdn.example.com', // Optional: custom domain
})
);Configuration Options
| Option | Type | Required | Description |
|---|---|---|---|
accountId | string | Yes* | Cloudflare account ID |
endpoint | string | Yes* | R2 endpoint (alternative to accountId) |
bucket | string | Yes | R2 bucket name |
accessKeyId | string | Yes | R2 API token access key |
secretAccessKey | string | Yes | R2 API token secret key |
publicUrl | string | No | Custom public URL for the bucket |
*Either accountId or endpoint is required.
Getting R2 Credentials
- Go to Cloudflare Dashboard → R2
- Create a bucket
- Click “Manage R2 API Tokens”
- Create a token with read/write permissions
- Copy the Access Key ID and Secret Access Key
Basic Usage
const result = await uploader.upload(file, {
folder: 'uploads',
});
console.log(result.url);
// https://cdn.example.com/uploads/file.jpgUpload with Progress
const result = await uploader.upload(file, {
folder: 'uploads',
onProgress: (percent) => {
console.log(`Upload progress: ${percent}%`);
}
});Batch Uploads
const results = await uploader.uploadMultiple(files, {
folder: 'batch-uploads',
concurrency: 5,
onBatchProgress: (completed, total) => {
console.log(`Uploaded ${completed}/${total} files`);
}
});Why R2?
- Zero egress fees - Free outbound data transfer
- S3-compatible - Easy migration from S3
- Global distribution - Cloudflare’s edge network
- Cost-effective - Only pay for storage and operations
Supported Features
R2 is storage-only:
uploader.supports('transformations.resize') // false
uploader.supports('capabilities.signedUploads') // true
uploader.supports('capabilities.multipartUpload') // trueNative SDK Access
Access the underlying S3-compatible client:
const client = uploader.provider.native;
const { ListObjectsV2Command } = await import('@aws-sdk/client-s3');
const objects = await client.send(new ListObjectsV2Command({
Bucket: 'my-bucket'
}));Adding Transformations
Use Cloudflare Images for image transformations, or consider Cloudinary for built-in support.
Environment Variables
CLOUDFLARE_ACCOUNT_ID=your-account-id
R2_BUCKET=my-bucket
R2_ACCESS_KEY_ID=your-access-key
R2_SECRET_ACCESS_KEY=your-secret-key
R2_PUBLIC_URL=https://cdn.example.comLast updated on