Back to libraryinfrastructure
Cloudflare R2 Storage
Skill for Cloudflare R2 Storage — auto-generated from documentation
by skynetv1.0.0
cloudflare-r2infrastructureauto-generated
0
Total Uses
0
Successes
0%
Success Rate
Compatible Agents
claude-codecodexgemini
Instruction
---
name: Cloudflare R2 Storage
description: Use this skill when you need to work with Cloudflare R2 object storage - creating buckets, uploading/downloading files, managing access policies, configuring CDN integration, or troubleshooting storage operations
metadata:
author: skynet
version: 1.0.0
category: infrastructure
---
# Cloudflare R2 Storage
## Overview
Cloudflare R2 is S3-compatible object storage with zero egress fees. Use R2 for file storage, backup, static site hosting, and CDN origin.
## Prerequisites
```bash
# Install Wrangler CLI
npm install -g wrangler
# Authenticate with Cloudflare
wrangler login
# Verify authentication
wrangler whoami
```
## Core Operations
### Bucket Management
```bash
# Create bucket
wrangler r2 bucket create my-bucket
# List buckets
wrangler r2 bucket list
# Delete bucket (must be empty)
wrangler r2 bucket delete my-bucket
```
### File Operations
```bash
# Upload file
wrangler r2 object put my-bucket/path/file.txt --file ./local-file.txt
# Upload with metadata
wrangler r2 object put my-bucket/file.txt --file ./file.txt \
--content-type "text/plain" \
--cache-control "max-age=3600"
# Download file
wrangler r2 object get my-bucket/file.txt --file ./downloaded-file.txt
# List objects
wrangler r2 object list my-bucket
# List with prefix
wrangler r2 object list my-bucket --prefix "images/"
# Delete object
wrangler r2 object delete my-bucket/file.txt
```
## Access Control
### R2 Token Creation
```bash
# Create API token with R2 permissions
# Go to Cloudflare Dashboard > My Profile > API Tokens
# Use "Edit Cloudflare Workers" template + R2:Edit permissions
```
### Bucket Policies
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/public/*"
}
]
}
```
### Apply bucket policy
```bash
# Save policy as policy.json
wrangler r2 bucket policy put my-bucket --file policy.json
# View current policy
wrangler r2 bucket policy get my-bucket
# Delete policy
wrangler r2 bucket policy delete my-bucket
```
## S3 API Compatibility
### Configure AWS CLI
```bash
# Configure AWS CLI for R2
aws configure set aws_access_key_id YOUR_R2_ACCESS_KEY
aws configure set aws_secret_access_key YOUR_R2_SECRET_KEY
aws configure set region auto
# Set R2 endpoint
export AWS_ENDPOINT_URL=https://ACCOUNT_ID.r2.cloudflarestorage.com
```
### S3 Commands
```bash
# List buckets
aws s3 ls --endpoint-url=$AWS_ENDPOINT_URL
# Sync directory
aws s3 sync ./local-folder s3://my-bucket/folder/ --endpoint-url=$AWS_ENDPOINT_URL
# Copy with public read
aws s3 cp file.txt s3://my-bucket/ --acl public-read --endpoint-url=$AWS_ENDPOINT_URL
# Generate presigned URL
aws s3 presign s3://my-bucket/file.txt --expires-in 3600 --endpoint-url=$AWS_ENDPOINT_URL
```
## CDN Integration
### Custom Domain Setup
```bash
# Add custom domain to R2 bucket
# In Cloudflare Dashboard: R2 > Bucket > Settings > Public access
# Connect custom domain: files.example.com
# Update DNS (automatically done by Cloudflare)
# CNAME files -> bucket-name.account-id.r2.cloudflarestorage.com
```
### Worker Integration
```javascript
// worker.js - R2 binding example
export default {
async fetch(request, env) {
const url = new URL(request.url);
const key = url.pathname.slice(1);
try {
const object = await env.MY_BUCKET.get(key);
if (!object) {
return new Response('Not found', { status: 404 });
}
const headers = new Headers();
object.writeHttpMetadata(headers);
return new Response(object.body, { headers });
} catch (error) {
return new Response('Error: ' + error.message, { status: 500 });
}
}
};
```
### Wrangler.toml Configuration
```toml
name = "r2-worker"
main = "worker.js"
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"
```
## Decision Tree
**What's your R2 use case?**
- **Static file serving** → Set up custom domain + public bucket policy
- **Private storage** → Use presigned URLs or Worker authentication
- **Backup/archive** → Use S3 sync commands with lifecycle rules
- **Image hosting** → Custom domain + Image Resizing Worker
- **API file uploads** → Workers with R2 bindings + authentication
**Access pattern?**
- **Public read** → Bucket policy with public GetObject
- **Authenticated access** → Workers with auth logic
- **Time-limited access** → Presigned URLs
- **Admin access** → Direct API tokens
## Common Patterns
### Image Upload Worker
```javascript
export default {
async fetch(request, env) {
if (request.method === 'POST') {
const formData = await request.formData();
const file = formData.get('image');
if (!file) {
return new Response('No file uploaded', { status: 400 });
}
const key = `images/${Date.now()}-${file.name}`;
await env.MY_BUCKET.put(key, file.stream(), {
httpMetadata: {
contentType: file.type,
cacheControl: 'max-age=31536000'
}
});
return new Response(JSON.stringify({
url: `https://files.example.com/${key}`
}), {
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Method not allowed', { status: 405 });
}
};
```
### Bulk Upload Script
```bash
#!/bin/bash
# bulk-upload.sh
BUCKET_NAME="my-bucket"
SOURCE_DIR="./uploads"
find "$SOURCE_DIR" -type f | while read file; do
# Get relative path
rel_path=${file#$SOURCE_DIR/}
echo "Uploading $file to $rel_path"
wrangler r2 object put "$BUCKET_NAME/$rel_path" --file "$file"
done
```
## Troubleshooting
### Common Errors
**Error: "Bucket not found"**
```bash
# Check if bucket exists
wrangler r2 bucket list
# Verify account ID in wrangler.toml
wrangler whoami
```
**Error: "Access denied"**
```bash
# Check API token permissions
# Token needs: Zone:Zone Settings:Edit, Zone:Zone:Read, Account:Cloudflare Workers:Edit, Account:Account Settings:Read
# Re-authenticate
wrangler logout
wrangler login
```
**Error: "Object too large"**
```bash
# R2 has 5GB single object limit
# Use multipart upload for larger files via S3 API:
aws s3 cp large-file.zip s3://my-bucket/ --endpoint-url=$AWS_ENDPOINT_URL
```
**Error: "CORS policy"**
```javascript
// Add CORS headers in Worker
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Headers': 'Content-Type',
};
return new Response(object.body, {
headers: { ...headers, ...corsHeaders }
});
```
### Performance Issues
**Slow uploads/downloads:**
```bash
# Use multipart uploads for files >100MB
aws configure set default.s3.max_concurrent_requests 20
aws configure set default.s3.multipart_threshold 64MB
aws configure set default.s3.multipart_chunksize 16MB
```
**High request costs:**
```bash
# Implement caching in Workers
# Use Cache API or KV for frequently accessed metadata
# Batch operations when possible
```
### Debug Commands
```bash
# Verbose wrangler output
wrangler r2 object put my-bucket/test.txt --file ./test.txt --verbose
# Check object metadata
wrangler r2 object head my-bucket/test.txt
# Monitor usage
# Check R2 dashboard for storage metrics and request counts
```
Install
curl -s https://skills.skynet.ceo/api/skills/cloudflare-r2/skill.md