Manage Cloudflare R2 object storage for file hosting using Wrangler CLI...
Manage Cloudflare R2 object storage using the Wrangler CLI. R2 provides S3-compatible storage with zero egress fees.
# Install Wrangler CLI
npm install -g wrangler
# Authenticate
wrangler login
# Verify authentication
wrangler whoami
wrangler r2 bucket list
wrangler r2 bucket create bucket-name
wrangler r2 bucket info bucket-name
wrangler r2 bucket delete bucket-name
IMPORTANT: By default, Wrangler uses local development storage. Use --remote flag for cloud operations.
# Upload to remote (production)
wrangler r2 object put bucket-name/path/to/file.png --file=local/file.png --remote
# Upload with content type
wrangler r2 object put bucket-name/image.jpg --file=image.jpg --content-type=image/jpeg --remote
# Upload all PNG files
for file in *.png; do
wrangler r2 object put "bucket-name/images/$file" --file="$file" --remote
done
wrangler r2 object get bucket-name/path/to/file.png --file=downloaded.png --remote
wrangler r2 object delete bucket-name/path/to/file.png --remote
wrangler r2 bucket dev-url enable bucket-name -y
wrangler r2 bucket dev-url get bucket-name
Example output:
Public access is enabled at 'https://pub-abc123.r2.dev'
wrangler r2 bucket dev-url disable bucket-name
# Test with curl
curl -I "https://pub-abc123.r2.dev/path/to/file.png"
# Should return HTTP 200 OK with Content-Type header
wrangler r2 bucket domain list bucket-name
assets.example.com CNAME bucket-name.r2.cloudflarestorage.com
wrangler r2 bucket cors list bucket-name
Create cors.json:
{
"CORSRules": [
{
"AllowedOrigins": ["*"],
"AllowedMethods": ["GET"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3600
}
]
}
Apply CORS:
wrangler r2 bucket cors set bucket-name cors.json
wrangler r2 bucket cors delete bucket-name
cd image-directory
# Upload all images to image-refs/ path
for file in IMG_*.png; do
echo "Uploading $file..."
wrangler r2 object put "bucket-name/image-refs/$file" --file="$file" --remote
done
# Verify uploads
curl -I "https://pub-abc123.r2.dev/image-refs/IMG_0821.png"
# Simply re-upload to overwrite
wrangler r2 object put "bucket-name/path/file.png" --file=new-file.png --remote
Symptom: Upload succeeds but files not in cloud bucket
Solution: Add --remote flag to all commands:
wrangler r2 object put bucket-name/file.png --file=file.png --remote
# Re-authenticate
wrangler logout
wrangler login
Check:
wrangler r2 bucket dev-url get bucket-name--remote flagSymptom: Browser blocks requests even though URLs work in curl
Solution: Configure CORS rules (see CORS Configuration section)
R2 Pricing (2024):
Example Cost (100 images, 150MB):
This version (4.24.3) syntax:
# Object operations
wrangler r2 object put bucket-name/path --file=file --remote
wrangler r2 object get bucket-name/path --file=output --remote
wrangler r2 object delete bucket-name/path --remote
# Bucket info
wrangler r2 bucket info bucket-name
# Dev URL
wrangler r2 bucket dev-url get bucket-name
wrangler r2 bucket dev-url enable bucket-name -y
# CORS
wrangler r2 bucket cors list bucket-name
Newer versions may use different syntax - check wrangler r2 --help for your version.
Bucket: mystica-assets
Public URL: https://pub-1f07f440a8204e199f8ad01009c67cf5.r2.dev/
Images Path: image-refs/
Upload images:
cd /Users/silasrhyneer/Code/new-mystica/docs/image-refs
for file in IMG_*.png; do
wrangler r2 object put "mystica-assets/image-refs/$file" --file="$file" --remote
done
Use in scripts:
npx tsx scripts/generate-image.ts \
--type "Weapon" \
--materials "fire,steel" \
--provider gemini \
-r "https://pub-1f07f440a8204e199f8ad01009c67cf5.r2.dev/image-refs/IMG_0821.png,https://pub-1f07f440a8204e199f8ad01009c67cf5.r2.dev/image-refs/IMG_2791.png"
docs/external/r2-image-hosting.md.claude/skills/generate-item-image.md