Configure the binding
To add a bucket, declare it in thewrangler.json file:
wrangler.json
- The
bindingandbucket_namekeys are required. - You don’t provision the bucket. celld creates it on first use.
- Deploy refuses every key other than
bindingandbucket_name, includingjurisdictionandpreview_bucket_name.
All bytes go through the Worker
The Worker receives each upload and sends each download. This design has the following consequences:- Your Worker does all authorization. Before a download, confirm that the user owns the key.
- You must stream all bodies. The isolate heap is 128 MB, so don’t read a large file into memory with
await request.arrayBuffer(). - For browser uploads, send the file as the raw request body, for example
fetch(url, { method: "PUT", body: file }). Therequest.formData()method keeps the full file in memory.
Upload a file
The following handler streams the request body into R2. Thejson function is a small helper that returns a JSON response.
index.js
- Pass
request.bodydirectly to theputmethod. - A streamed body has no known length. Check the size with the
content-lengthheader, or count the bytes in aTransformStream. - A streamed body of 8 MiB or more becomes a multipart upload automatically.
- Generate keys on the server. Don’t use a key from the client.
- Set
httpMetadata.contentTypeon eachputcall. To make the browser download the file instead of displaying it, also setcontentDisposition, for example'attachment; filename="report.csv"'.
Download a file
The following handler serves an object, with support for range requests and conditional requests:index.js
R2 API
The following table summarizes the methods of an R2 binding:
An
R2Object has the key, size, etag, httpEtag, uploaded, httpMetadata, customMetadata, and range properties. The version property is the same as the etag property.
Conditional calls work.
Keys
Object keys follow these rules:- A key is 1 to 1,024 bytes long.
- The namespace is flat.
a/b,/a/b,a//b, anda/b/are four different keys. - Use ASCII keys. The
listmethod sorts keys that contain non-ASCII or special characters in a different order from Cloudflare. - To query files by owner, name, or date, keep an index in D1.
Share a file with a link
R2 on celld has no presigned URLs. To share a file, generate a random token, and store the mapping from the token to the object key in KV with an expiry. Then serve the file from a Worker route. The following example assumes a KV binding namedLINKS next to the FILES bucket:
index.js
Differences from Cloudflare
celld differs from Cloudflare R2 in the following ways:- Presigned URLs, public buckets, the S3 API, event notifications, the
ssecKeyoption, and lifecycle rules aren’t available. - Deploy refuses the
jurisdictionandpreview_bucket_namekeys. - A multipart upload must finish on the node and process that started it.
- celld refuses a conditional
putof a streamed body over 8 MiB. - The
listmethod sorts keys with non-ASCII or special characters in a different order. - The
versionproperty of an object is the same as itsetag.