Configuration
R2 bindings in cloudflare.config.ts
Reference an R2 bucket with bindings.r2 and access it through your Worker environment. A binding does not make the bucket publicly accessible.
Quick configuration
import { bindings, defineConfig } from "cf/config";
export default defineConfig({
worker: {
name: "uploads-worker",
compatibilityDate: "2026-09-29",
entrypoint: "./src/index.ts",
env: {
UPLOADS: bindings.r2({ name: "notes-uploads" }),
},
},
});
UPLOADS becomes the binding on the Worker environment. The name option selects the bucket. The helper supports a bucket name, not the Wrangler field name bucket_name.
Create the bucket
# Inspect the operation before creating a remote bucket
cf r2 buckets create --help
# Authenticated operation; creates an account resource
cf r2 buckets create --name notes-uploads
Confirm the account and bucket jurisdiction. If your bucket belongs to a jurisdiction, the binding’s jurisdiction must match the resource you intend to use. Keep resource names distinct between staging and production when data must remain separate.
Read an object in a Worker
export default {
async fetch(_request: Request, env: { UPLOADS: R2Bucket }) {
const object = await env.UPLOADS.get("hello.txt");
if (!object) return new Response("Not found", { status: 404 });
const headers = new Headers();
object.writeHttpMetadata(headers);
headers.set("etag", object.httpEtag);
return new Response(object.body, { headers });
},
};
Generate the Cloudflare runtime types in your Worker project so R2Bucket is available to TypeScript. This example reads a fixed key; it is not an upload endpoint or an authorization policy.
An R2 binding gives Worker code access to a bucket. Public delivery through a custom domain or an r2.dev endpoint is a separate configuration decision. Do not infer public accessibility from the presence of the binding.
From Wrangler configuration
The Wrangler r2_buckets array uses binding and bucket_name. In the new config, worker.env.UPLOADS supplies the binding name and bindings.r2({ name: ... }) carries the bucket reference.
Use the official migration for existing configuration, then check bucket names and jurisdiction rather than replacing fields mechanically.
Common mistakes
- Using a bucket ID where the helper expects a name.
- Reading from a local simulation and expecting remote objects to appear.
- Assuming a binding automatically enables a public bucket URL.
- Returning object bodies without checking for a missing key.
Continue with the configuration guide or D1 if metadata belongs in a database while objects live in R2.