# Next.js boilerplate with Cloudflare R2

> S3-compatible object storage with no egress fees. You get a private bucket, presigned PUT uploads issued only after an authorisation check, and presigned downloads. Bucket CORS and lifecycle rules live in the repo as configuration. A token-only dropzone uploads straight to R2.

S3-compatible object storage with free egress. You pay for storage and requests.

- **Category:** Storage
- **Pricing:** Free each month: 10 GB stored, 1M Class A and 10M Class B operations. Then $0.015 per GB-month, $4.50 per million Class A operations (writes, lists) and $0.36 per million Class B operations (reads). Egress is free.
- **Best for:** Anything read far more often than it is written, and anything large. User uploads, video, model weights, datasets, backups you may need to pull out again.
- **Vendor docs:** https://developers.cloudflare.com/r2/

## Trade-offs

- No egress fee, but operations are billed. Many tiny reads can cost more than the bytes. Check Class B pricing against your access pattern, not just your storage volume.
- S3-compatible, not S3. The common surface works with the AWS SDK. Parts of the long tail (some checksum modes, ACLs, object lock, storage classes) do not. Test, do not assume.
- Authorisation is your job. R2 has no row level security, so "may this user read this key" is a decision your app makes on every request.
- A bucket is private until you attach a custom domain or enable the r2.dev subdomain, and r2.dev is rate-limited and not for production. Public serving means DNS work, not a checkbox.
- Strong read-after-write consistency, but no built-in image transforms. That is a separate Cloudflare product, or a resize on upload in your own code.
- Bucket config (CORS, lifecycle) lives in Cloudflare, not in your migrations. It needs its own committed files and a command to apply them. This battery ships both.

## Known fixes it ships

- [Orphaned objects in R2: lifecycle rules and the sweep they cannot do](https://agenticboilerplate.com/cookbook/r2/cleaning-up-orphaned-uploads): Direct-to-bucket uploads leak objects nobody references. Lifecycle rules clean up a tmp/ prefix and abandoned multipart parts; owner-scoped orphans need a reconciliation job.
- [The R2 upload that fails in the browser and works in curl: bucket CORS](https://agenticboilerplate.com/cookbook/r2/cors-on-a-bucket): A presigned PUT from a page is a cross-origin request. Without CORS rules on the bucket it fails with an error that never says CORS, and the signature gets blamed.
- [Serving R2 objects publicly: custom domains, r2.dev and cache headers](https://agenticboilerplate.com/cookbook/r2/custom-domains-and-cache-headers): r2.dev is rate-limited and not for production. A custom domain puts Cloudflare's cache in front of the bucket, but only if you wrote Cache-Control at upload time.
- [Presigned PUT or multipart: picking an upload strategy for R2](https://agenticboilerplate.com/cookbook/r2/presigned-put-vs-multipart): A single presigned PUT is right up to about 100 MB and restarts from zero when it fails. Above that, multipart is not an optimisation, it is the only thing that works.
- [Zero egress fees, and the workloads where R2 actually beats S3](https://agenticboilerplate.com/cookbook/r2/zero-egress-and-when-r2-beats-s3): Egress is the line that surprises people on an S3 bill. R2 charges nothing for it and charges for operations instead: here is the arithmetic for deciding, including where R2 loses.

## Generate it

[Build a repo with Cloudflare R2](https://agenticboilerplate.com/build?b=r2)

---

Agentic Boilerplate: A Next.js repo your agent already knows. Free during launch, then $99 once.

- Site map for agents: https://agenticboilerplate.com/llms.txt
- Public API: https://agenticboilerplate.com/openapi.json
- Contact: agenticstudio@gmail.com
