Skip to content
GitHubXDiscordRSS

R2Bucket

Learn how to create, configure, and manage Cloudflare R2 Buckets using Alchemy for scalable object storage.

Creates and manages Cloudflare R2 Buckets for object storage with S3 compatibility.

Create a basic R2 bucket with default settings:

import { R2Bucket } from "alchemy/cloudflare";
const bucket = await R2Bucket("my-bucket", {
name: "my-bucket",
});
import { Worker, R2Bucket } from "alchemy/cloudflare";
const bucket = await R2Bucket("my-bucket", {
name: "my-bucket",
});
await Worker("my-worker", {
name: "my-worker",
script: "console.log('Hello, world!')",
bindings: {
BUCKET: bucket,
},
});

Create a bucket with location hint for optimal performance:

import { R2Bucket } from "alchemy/cloudflare";
const euBucket = await R2Bucket("eu-bucket", {
name: "eu-bucket",
locationHint: "eu",
jurisdiction: "eu",
});

Create a development bucket with public access enabled:

import { R2Bucket } from "alchemy/cloudflare";
const publicBucket = await R2Bucket("public-assets", {
name: "public-assets",
allowPublicAccess: true,
});
console.log(publicBucket.domain); // [random-id].r2.dev

This enables the r2.dev domain for the bucket. This URL is rate-limited and not recommended for production use.

Create a bucket with CORS rules:

import { R2Bucket } from "alchemy/cloudflare";
const corsBucket = await R2Bucket("cors-bucket", {
name: "cors-bucket",
cors: [
{
allowed: {
origins: ["https://example.com"],
methods: ["GET", "POST", "PUT", "DELETE", "HEAD"],
headers: ["*"],
},
},
],
});

Create a bucket that will be automatically emptied when deleted:

import { R2Bucket } from "alchemy/cloudflare";
const tempBucket = await R2Bucket("temp-storage", {
name: "temp-storage",
empty: true, // All objects will be deleted when this resource is destroyed
});

Configure automatic transitions like aborting multipart uploads, deleting objects after an age or date, or moving objects to Infrequent Access.

import { R2Bucket } from "alchemy/cloudflare";
const bucket = await R2Bucket("logs", {
name: "logs",
lifecycle: [
// Abort incomplete multipart uploads after 7 days
{
id: "abort-mpu-7d",
conditions: { prefix: "" }, // empty means apply to all objects/uploads
enabled: true,
abortMultipartUploadsTransition: {
condition: { type: "Age", maxAge: 7 * 24 * 60 * 60 },
},
},
// Delete objects after 30 days
{
id: "delete-30d",
conditions: { prefix: "archive/" },
deleteObjectsTransition: {
condition: { type: "Age", maxAge: 30 * 24 * 60 * 60 },
},
},
// Transition storage class to InfrequentAccess after 60 days
{
id: "ia-60d",
conditions: { prefix: "cold/" },
storageClassTransitions: [
{
condition: { type: "Age", maxAge: 60 * 24 * 60 * 60 },
storageClass: "InfrequentAccess",
},
],
},
],
});
  • conditions.prefix: Scope rule to keys beginning with a prefix. Use "" for all keys.
  • enabled: Defaults to true when omitted.
  • Age condition fields: lifecycle uses maxAge (seconds).
  • Date condition fields: use ISO strings like "2025-01-01T00:00:00Z".

Apply retention locks to objects by age, until a fixed date, or indefinitely.

import { R2Bucket } from "alchemy/cloudflare";
const bucket = await R2Bucket("legal-holds", {
name: "legal-holds",
lock: [
// Lock all objects for 7 days
{
id: "retain-7d",
prefix: "",
enabled: true,
condition: { type: "Age", maxAgeSeconds: 7 * 24 * 60 * 60 },
},
// Indefinite lock for the legal prefix
{
id: "legal-indef",
prefix: "legal/",
condition: { type: "Indefinite" },
},
// Retain until a specific date
{
id: "retain-until-2025",
prefix: "exports/",
condition: { type: "Date", date: "2025-01-01T00:00:00Z" },
},
],
});
  • prefix: Scope the lock rule to objects starting with the prefix. Omit or set to "" for all keys.
  • enabled: Defaults to true when omitted.
  • Age condition fields: lock uses maxAgeSeconds (seconds).

Enable data catalog for the bucket.

import { R2Bucket } from "alchemy/cloudflare";
const bucket = await R2Bucket("my-bucket", {
name: "my-bucket",
dataCatalog: true,
});
console.log(bucket.catalog);

Use the returned R2Bucket instance to work with objects directly from your scripts.

import { R2Bucket } from "alchemy/cloudflare";
const bucket = await R2Bucket("my-bucket", {
name: "my-bucket",
});

Retrieve metadata about an object.

const head = await bucket.head("example.txt");
if (head) {
console.log(head.etag, head.size);
}

Retrieve an object from the bucket.

const obj = await bucket.get("example.txt");
const text = await obj?.text();

Upload an object to the bucket.

const putInfo = await bucket.put("example.txt", "Hello, R2!\n");

Delete an object from the bucket.

await bucket.delete("example.txt");

List objects in the bucket.

const list = await bucket.list();
console.log(list.objects.length);