# Workflow: R2 media pipeline

## 1. Two buckets

One bucket for public assets, one for private originals. Public means public, including future objects: never mix. Buckets are private by default, which is the safe starting point.

## 2. Custom domain for production

Expose the public bucket on a custom domain (`assets.example.com`). The `r2.dev` subdomain is for non-production use only. Verify from an unauthenticated session that the assets load with no credentials.

## 3. Upload pipeline

Uploads go through your app (or a Worker with the R2 binding) with content types set correctly: a missing `Content-Type` serves downloads instead of images. Fingerprint filenames for immutable caching.

## 4. Cache rules

Long edge TTLs on the fingerprinted assets; the custom domain's cache behavior tuned per path. Verify `CF-Cache-Status: HIT` on repeat loads from multiple regions.

## 5. Private originals

Serve private files via presigned URLs or through a Worker that checks auth and streams from the R2 binding. The Worker path also lets you add transforms (resizing, format negotiation) at the edge.

## Checklist

- Public and private buckets separated from day one.
- Custom domain in production, content types correct, cache HIT verified.
- No sensitive file ever lands in the public bucket.