Cloudflare R2 S3-compatible object storage. Use for buckets, uploads, CORS, presigned URLs, or encountering R2_ERROR, CORS failures, multipart issues.
View on GitHubsecondsky/claude-skills
cloudflare-r2
January 24, 2026
Select agents to install to:
npx add-skill https://github.com/secondsky/claude-skills/blob/main/plugins/cloudflare-r2/skills/cloudflare-r2/SKILL.md -a claude-code --skill cloudflare-r2Installation paths:
.claude/skills/cloudflare-r2/# Cloudflare R2 Object Storage
**Status**: Production Ready ✅ | **Last Verified**: 2025-12-27 | **v3.0.0**
**Contents**: [Quick Start](#quick-start-5-minutes) • [New Features](#new-r2-features-2025) • [Core R2 API](#core-r2-workers-api-quick-reference) • [Critical Rules](#critical-rules) • [Agents & Commands](#available-agents--commands) • [References](#when-to-load-references)
---
## Quick Start (5 Minutes)
### 1. Create R2 Bucket
```bash
bunx wrangler r2 bucket create my-bucket
```
**Bucket naming:** 3-63 chars, lowercase, numbers, hyphens only
### 2. Configure Binding
Add to `wrangler.jsonc`:
```jsonc
{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2025-10-11",
"r2_buckets": [
{
"binding": "MY_BUCKET", // env.MY_BUCKET
"bucket_name": "my-bucket", // Actual bucket
"preview_bucket_name": "my-bucket-preview" // Optional: dev bucket
}
]
}
```
**CRITICAL:** `binding` = code access name, `bucket_name` = actual R2 bucket
### 3. Basic Upload/Download
```typescript
import { Hono } from 'hono';
type Bindings = {
MY_BUCKET: R2Bucket;
};
const app = new Hono<{ Bindings: Bindings }>();
// Upload
app.put('/upload/:filename', async (c) => {
const filename = c.req.param('filename');
const body = await c.req.arrayBuffer();
const object = await c.env.MY_BUCKET.put(filename, body, {
httpMetadata: {
contentType: c.req.header('content-type') || 'application/octet-stream',
},
});
return c.json({
success: true,
key: object.key,
size: object.size,
});
});
// Download
app.get('/download/:filename', async (c) => {
const object = await c.env.MY_BUCKET.get(c.req.param('filename'));
if (!object) {
return c.json({ error: 'Not found' }, 404);
}
return new Response(object.body, {
headers: {
'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream',
'ETag': object.httpEtag,
},
});
});
export default app;
```