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.

Beta tooling changes quickly. Examples are checked against cf 1.0.0-beta.5 and @cloudflare/config 0.20.0. See the sources below.

Quick configuration

cloudflare.config.ts
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

Terminal
# 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

src/index.ts
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.

Sources & verification

Cloudflare configuration types and helperscf CLI source and READMEUse R2 from Workers