Complete knowledge domain for Cloudflare R2 - S3-compatible object storage on Cloudflare's edge network. Use when: creating R2 buckets, uploading files to R2, downloading objects, configuring R2 bindings, setting up CORS, generating presigned URLs, multipart uploads, storing images/assets, managing object metadata, or encountering "R2_ERROR", CORS errors, presigned URL failures, multipart upload issues, or storage quota errors. Keywords: r2, r2 storage, cloudflare r2, r2 bucket, r2 upload, r2 download, r2 binding, object storage, s3 compatible, r2 cors, presigned urls, multipart upload, r2 api, r2 workers, file upload, asset storage, R2_ERROR, R2Bucket, r2 metadata, custom metadata, http metadata, content-type, cache-control, aws4fetch, s3 client, bulk delete, r2 list, storage class
Complete knowledge domain for Cloudflare R2 - S3-compatible object storage on Cloudflare's global network.
This skill provides complete R2 knowledge including:
| Issue | Description | Prevention |
|-------|-------------|------------|
| CORS errors | Browser uploads fail | Configure CORS before browser access |
| Binary downloads | Files download as binary blob | Always set contentType on upload |
| Presigned URL security | URLs never expire | Set X-Amz-Expires parameter |
| Multipart limits | Upload fails with large files | Use 5MB-100MB parts, max 10,000 parts |
| Bulk delete limits | Deleting >1000 keys fails | Chunk into batches of 1000 |
| Metadata overflow | Custom metadata exceeds 2KB | Keep total metadata under 2KB |
import { Hono } from 'hono';
type Bindings = {
MY_BUCKET: R2Bucket;
};
const app = new Hono<{ Bindings: Bindings }>();
// Upload file
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 file
app.get('/download/:filename', async (c) => {
const filename = c.req.param('filename');
const object = await c.env.MY_BUCKET.get(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;
SKILL.md - Complete R2 knowledge domaintemplates/wrangler-r2-config.jsonc - R2 binding configurationtemplates/r2-simple-upload.ts - Basic upload/download Workertemplates/r2-multipart-upload.ts - Multipart upload Workertemplates/r2-presigned-urls.ts - Presigned URL generatortemplates/r2-cors-config.json - CORS policy examplesreference/workers-api.md - Complete Workers API referencereference/s3-compatibility.md - S3 API compatibility notesreference/common-patterns.md - Common R2 patterns✅ Production Ready
This skill is based on:
Last Updated: 2025-10-21 Status: Production Ready ✅ Maintainer: Jeremy Dawes | jeremy@jezweb.net
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer