Cloudflare R2
Configure Cloudflare R2 as the S3-compatible bucket for TurboJet.
Cloudflare R2 is S3-compatible object storage with zero egress fees. It is the default provider documented in .env.example and Environment.
1. Create a bucket
In the Cloudflare dashboard → R2 → create a bucket. Keep it private (no public access). TurboJet uses presigned URLs for upload and download.
2. Create an API token
Create an R2 API token with Object Read & Write on that bucket. Copy the Access Key ID and Secret Access Key.
3. Configure CORS
On the bucket, set CORS so browsers can upload from your marketing origin:
- Allowed origins:
NEXT_PUBLIC_MARKETING_URL(and local marketing URL in development) - Allowed methods:
PUT,GET,HEAD - Allowed headers: include
Content-Type
4. Environment variables
S3_ACCESS_KEY_ID="your-r2-access-key-id"
S3_SECRET_ACCESS_KEY="your-r2-secret-access-key"
S3_ENDPOINT="https://<ACCOUNT_ID>.r2.cloudflarestorage.com"
S3_BUCKET="your-bucket-name"
S3_REGION="auto"
# Optional — only if you need GET /api/storage/public
# S3_PUBLIC_URL="https://pub-<hash>.r2.dev"Replace <ACCOUNT_ID> with your Cloudflare account ID.
5. Test an upload
Start the marketing app and call the upload flow while authenticated. Missing or incomplete S3_* keys yield 503 Storage is not configured.
Public URLs (optional)
Set S3_PUBLIC_URL only if you intentionally expose objects via an r2.dev subdomain or custom domain. Prefer signed URLs for private user files.
FAQ
Why R2 instead of S3?
If you serve many or large files, R2’s zero egress pricing is often cheaper. If you already live in AWS, AWS S3 integrates with the rest of that ecosystem.
Do I need public access?
No. Keep the bucket private and use /api/storage/signed.