CloudflareStorage is the Storage component’s Cloudflare R2 backend. It extends the shared Storage base class, which talks to R2 through Bun’s built-in S3 client (R2 is S3-compatible), so you get production object storage with zero egress fees behind the same IStorage interface as every other backend. Switch to or from R2 without changing a single call site.
What R2 brings here
Because R2 speaks S3, the backend runs on Bun’s nativeS3Client and CloudflareStorage only supplies the connection options. The interface is the same IStorage you use elsewhere: put, getFile, getAsJson, delete, list, and the rest. All transport logic lives in the Storage base class, so the subclass provides only credentials and getOptions(). put() accepts strings, ArrayBuffer, Blob, Request/Response, and BunFile/S3File. The class registers with @decorator.storage() and resolves from the container.
Installation
CloudflareStorage ships with @talosjs/storage. It uses Bun’s built-in S3 client, so there’s no extra SDK to install.
Environment variables
CloudflareStorage is constructed, so missing credentials fail fast at startup.
How it works
CloudflareStorage reads its credentials, then getOptions() returns the S3Options the base Storage class uses to build a Bun.S3Client. Calling setBucket() constructs (or rebuilds) the client for that bucket, and from then on every read and write goes through the S3 client. The active bucket is the R2 bucket the client targets.
Usage
The API is the same as every other storage backend.Custom buckets
Register a named storage under your own class so each bucket has a dedicated, injectable type:Use in the app
In an@talosjs/app application, storage isn’t a dedicated App config slot. CloudflareStorage registers itself with the container through @decorator.storage() as soon as the class is imported, and you inject it wherever you read or write files.
IStorage methods:
@decorator.storage():
STORAGE_CLOUDFLARE_ACCESS_KEY, STORAGE_CLOUDFLARE_SECRET_KEY, STORAGE_CLOUDFLARE_ENDPOINT, and (optionally) STORAGE_CLOUDFLARE_REGION in your .env.yml (or environment) so the backend can connect.
Exceptions
CloudflareStorage throws StorageException on misconfiguration or a failed operation, carrying a machine-readable key.
Working with R2 day to day
CallsetBucket() before any read or write, since that call also builds the S3 client for the bucket. Point STORAGE_CLOUDFLARE_ENDPOINT at your account’s R2 S3 endpoint rather than the public bucket URL. Group objects under stable prefixes like avatars/123.png to keep list() and clearBucket() predictable, and prefer getAsStream() and putFile/putDir over loading whole files into memory. Keep the access key, secret key, and endpoint in .env, never in source. When you want a bucket to be injectable on its own, register a CloudflareStorage subclass for it so it carries its own type.
See the Storage component for the full interface and the other backends, including Bunny Storage.