FluxMedia
Copy page
Open in ChatGPTOpen in Claude

Cloudflare R2 Provider

Cost-effective storage with zero egress fees.

Installation

pnpm add @fluxmedia/core @fluxmedia/r2 @aws-sdk/client-s3 @aws-sdk/lib-storage

R2 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

  1. Go to Cloudflare Dashboard → R2
  2. Create a bucket
  3. Click "Manage R2 API Tokens"
  4. Create a token with read/write permissions
  5. 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.jpg
console.log(result.storageKey); // uploads/file.jpg

Upload with Progress

const result = await uploader.upload(file, {
  folder: 'uploads',
  onProgress: (percent) => {
    console.log(`Upload progress: ${percent}%`);
  },
  onByteProgress: (loaded, total) => {
    console.log(`${loaded}/${total} bytes`);
  },
});

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'); // true

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