Skip to content
GitHubXDiscordRSS

R2Bucket

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).