Skip to main content
Cloudflare R2 is S3-compatible object storage with zero egress fees, and Blaze puts it directly on req.env.R2 in every handler. Whether you need to accept file uploads, serve assets, or build a private document store, R2 fits naturally into any Blaze route — no SDK to initialize, no credentials to manage beyond your wrangler.toml binding.

Configure the binding

1

Add the bucket to wrangler.toml

wrangler.toml
2

Define the Env type

src/types/env.ts
3

Pass Env to createApp

src/index.ts

Uploading a file

Read the raw request body with req.arrayBuffer(), then call req.env.R2.put(key, body, options). Pass httpMetadata to preserve the content type and customMetadata to store any application-level attributes alongside the object.
R2 objects are limited to 5 TB per object. For uploads larger than a few hundred MB, consider using R2’s multipart upload API via a presigned URL so the client streams directly to R2 instead of buffering through your Worker.

Downloading a file

req.env.R2.get(key) returns an R2ObjectBody when the object exists or null when it does not. Always check for null before accessing the body, then forward the content type and ETag headers before streaming the response.

Listing objects

req.env.R2.list() returns the first page of objects in the bucket. Use the prefix option to scope results to a virtual directory and cursor to paginate through large buckets.

Deleting objects

req.env.R2.delete(key) removes a single object. Deleting a key that does not exist is a no-op — R2 returns success regardless.

Metadata and ETags

Every R2 object exposes httpMetadata (standard HTTP headers stored at upload time) and httpEtag (a content fingerprint). Use these to power proper browser caching without any extra computation in your Worker.
When serving files to browsers, set the ETag header and let Blaze’s etag middleware handle If-None-Match negotiation automatically, returning a 304 Not Modified when the client already holds a fresh copy:
Use Blaze’s built-in etag middleware alongside R2’s native httpEtag for conditional GET support out of the box. The middleware intercepts If-None-Match request headers and short-circuits the handler with a 304 response when the ETag matches — saving both bandwidth and R2 read costs on frequently accessed objects.