R2
What it is
R2 is Cloudflare's object storage — a place to put files: images, videos, backups, user uploads, build artifacts. It speaks the same API as Amazon S3, so most S3 tools and SDKs work against it unchanged. The headline difference is pricing: R2 charges for storage and operations but no egress fees, so serving data out is free.
Strengths
- Zero egress fees — a major saving for media-heavy or download-heavy apps.
- S3-compatible API, so existing tooling and libraries just work.
- Bind it directly to a Worker for reads and writes with no credentials in code.
- Can sit behind Cloudflare's CDN for fast, cached delivery.
- Scales to large objects and large buckets without provisioning.
Trade-offs
- Object storage, not a filesystem or database — no querying inside files.
- Operations (PUT/GET/LIST) are billed, so chatty access patterns add up.
- Strong consistency and features differ in details from S3; check edge cases.
- For tiny, frequently-mutated values, KV or D1 is a better fit.
When to use it
Use R2 for user uploads, generated files, large static assets, data exports, and backups — especially anywhere bandwidth costs on S3 would hurt.
Vibe coding fit
R2 plays well with AI-directed builds because the binding removes the usual credential dance — the agent writes to env.BUCKET directly. Tell the agent whether files are public (serve via a Worker or custom domain) or private (signed access), so it wires delivery correctly. The example binds a bucket and uploads a file from the CLI.
# wrangler.toml
[[r2_buckets]]
binding = "BUCKET"
bucket_name = "uploads"
npx wrangler r2 bucket create uploads
npx wrangler r2 object put uploads/logo.png --file ./logo.png