Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/r2/api.md
1# R2 API Reference23## PUT (Upload)45```typescript6// Basic7await env.MY_BUCKET.put(key, value);89// With metadata10await env.MY_BUCKET.put(key, value, {11httpMetadata: {12contentType: 'image/jpeg',13contentDisposition: 'attachment; filename="photo.jpg"',14cacheControl: 'max-age=3600'15},16customMetadata: { userId: '123', version: '2' },17storageClass: 'Standard', // or 'InfrequentAccess'18sha256: arrayBufferOrHex, // Integrity check19ssecKey: arrayBuffer32bytes // SSE-C encryption20});2122// Value types: ReadableStream | ArrayBuffer | string | Blob23```2425## GET (Download)2627```typescript28const object = await env.MY_BUCKET.get(key);29if (!object) return new Response('Not found', { status: 404 });3031// Body: arrayBuffer(), text(), json(), blob(), body (ReadableStream)3233// Ranged reads34const object = await env.MY_BUCKET.get(key, { range: { offset: 0, length: 1024 } });3536// Conditional GET37const object = await env.MY_BUCKET.get(key, { onlyIf: { etagMatches: '"abc123"' } });38```3940## HEAD (Metadata Only)4142```typescript43const object = await env.MY_BUCKET.head(key); // Returns R2Object without body44```4546## DELETE4748```typescript49await env.MY_BUCKET.delete(key);50await env.MY_BUCKET.delete([key1, key2, key3]); // Batch (max 1000)51```52## LIST5354```typescript55const listed = await env.MY_BUCKET.list({56limit: 1000,57prefix: 'photos/',58cursor: cursorFromPrevious,59delimiter: '/',60include: ['httpMetadata', 'customMetadata']61});6263// Pagination (always use truncated flag)64while (listed.truncated) {65const next = await env.MY_BUCKET.list({ cursor: listed.cursor });66listed.objects.push(...next.objects);67listed.truncated = next.truncated;68listed.cursor = next.cursor;69}70```7172## Multipart Uploads7374```typescript75const multipart = await env.MY_BUCKET.createMultipartUpload(key, {76httpMetadata: { contentType: 'video/mp4' }77});7879const uploadedParts: R2UploadedPart[] = [];80for (let i = 0; i < partCount; i++) {81const part = await multipart.uploadPart(i + 1, partData);82uploadedParts.push(part);83}8485const object = await multipart.complete(uploadedParts);86// OR: await multipart.abort();8788// Resume89const multipart = env.MY_BUCKET.resumeMultipartUpload(key, uploadId);90```9192## Presigned URLs (S3 SDK)9394```typescript95import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';96import { getSignedUrl } from '@aws-sdk/s3-request-presigner';9798const s3 = new S3Client({99region: 'auto',100endpoint: `https://${accountId}.r2.cloudflarestorage.com`,101credentials: { accessKeyId: env.R2_ACCESS_KEY_ID, secretAccessKey: env.R2_SECRET_ACCESS_KEY }102});103104const uploadUrl = await getSignedUrl(s3, new PutObjectCommand({ Bucket: 'my-bucket', Key: key }), { expiresIn: 3600 });105return Response.json({ uploadUrl });106```107108## TypeScript Interfaces109110```typescript111interface R2Bucket {112head(key: string): Promise<R2Object | null>;113get(key: string, options?: R2GetOptions): Promise<R2ObjectBody | null>;114put(key: string, value: ReadableStream | ArrayBuffer | string | Blob, options?: R2PutOptions): Promise<R2Object | null>;115delete(keys: string | string[]): Promise<void>;116list(options?: R2ListOptions): Promise<R2Objects>;117createMultipartUpload(key: string, options?: R2MultipartOptions): Promise<R2MultipartUpload>;118resumeMultipartUpload(key: string, uploadId: string): R2MultipartUpload;119}120121interface R2Object {122key: string; version: string; size: number;123etag: string; httpEtag: string; // httpEtag is quoted, use for headers124uploaded: Date; httpMetadata?: R2HTTPMetadata;125customMetadata?: Record<string, string>;126storageClass: 'Standard' | 'InfrequentAccess';127checksums: R2Checksums;128writeHttpMetadata(headers: Headers): void;129}130131interface R2ObjectBody extends R2Object {132body: ReadableStream; bodyUsed: boolean;133arrayBuffer(): Promise<ArrayBuffer>; text(): Promise<string>;134json<T>(): Promise<T>; blob(): Promise<Blob>;135}136137interface R2HTTPMetadata {138contentType?: string; contentDisposition?: string;139contentEncoding?: string; contentLanguage?: string;140cacheControl?: string; cacheExpiry?: Date;141}142143interface R2PutOptions {144httpMetadata?: R2HTTPMetadata | Headers;145customMetadata?: Record<string, string>;146sha256?: ArrayBuffer | string; // Only ONE checksum allowed147storageClass?: 'Standard' | 'InfrequentAccess';148ssecKey?: ArrayBuffer;149}150151interface R2GetOptions {152onlyIf?: R2Conditional | Headers;153range?: R2Range | Headers;154ssecKey?: ArrayBuffer;155}156157interface R2ListOptions {158limit?: number; prefix?: string; cursor?: string; delimiter?: string;159startAfter?: string; include?: ('httpMetadata' | 'customMetadata')[];160}161162interface R2Objects {163objects: R2Object[]; truncated: boolean;164cursor?: string; delimitedPrefixes: string[];165}166167interface R2Conditional {168etagMatches?: string; etagDoesNotMatch?: string;169uploadedBefore?: Date; uploadedAfter?: Date;170}171172interface R2Range { offset?: number; length?: number; suffix?: number; }173174interface R2Checksums {175md5?: ArrayBuffer; sha1?: ArrayBuffer; sha256?: ArrayBuffer;176sha384?: ArrayBuffer; sha512?: ArrayBuffer;177}178179interface R2MultipartUpload {180key: string;181uploadId: string;182uploadPart(partNumber: number, value: ReadableStream | ArrayBuffer | string | Blob): Promise<R2UploadedPart>;183abort(): Promise<void>;184complete(uploadedParts: R2UploadedPart[]): Promise<R2Object>;185}186187interface R2UploadedPart {188partNumber: number;189etag: string;190}191```192193## CLI Operations194195```bash196wrangler r2 object put my-bucket/file.txt --file=./local.txt197wrangler r2 object get my-bucket/file.txt --file=./download.txt198wrangler r2 object delete my-bucket/file.txt199wrangler r2 object list my-bucket --prefix=photos/200```201