This Cloudflare Workers project automatically transfers video files from Cloudflare R2 storage to Cloudflare Stream for optimized video delivery. When a video file is uploaded to R2, it triggers a queue message that processes the file and creates a Stream video asset.
- R2 Bucket: Stores original video files
- Queue Consumer: Processes upload notifications
- Cloudflare Stream: Hosts and delivers optimized videos
- KV Storage: Stores mapping between R2 objects and Stream URLs
- Cloudflare account with access to:
- Cloudflare Workers
- Cloudflare R2
- Cloudflare Stream
- Cloudflare KV
- Cloudflare Queues
- Node.js and pnpm installed
- Wrangler CLI installed (
npm install -g wrangler)
git clone <your-repo>
cd r2-auto-stream
pnpm installwrangler loginwrangler r2 bucket create your-source-bucketwrangler kv namespace create "STREAM_URLS"
wrangler kv namespace create "STREAM_URLS" --previewwrangler queues create video-processing-queue- Go to Cloudflare Dashboard → R2 → Manage R2 API tokens
- Create a new R2 API token with:
- Permissions: Object Read & Write
- Bucket: Your source bucket
- Note down the Access Key ID and Secret Access Key
- Go to Cloudflare Dashboard → Manage Account (on the left sidebar) → Account API Tokens
- or go to Cloudflare Dashboard → My Profile → API Tokens
- Create a custom token with:
- Permissions:
- Account - Cloudflare Stream:Edit
- Account Resources: Include your account
- Zone Resources: All zones (if needed)
- Permissions:
- Note down the API Token
Create or update your wrangler.jsonc file:
Set the required secrets using Wrangler:
wrangler secret put R2_SOURCE_BUCKET
wrangler secret put R2_ACCESS_KEY_ID
wrangler secret put R2_SECRET_ACCESS_KEY
wrangler secret put CLOUDFLARE_ACCOUNT_ID
wrangler secret put CLOUDFLARE_API_TOKEN
wrangler secret put ALLOWED_ORIGINSSet up R2 to send notifications to your queue when objects are created:
- Go to Cloudflare Dashboard → R2 → Your Bucket → Settings
- Create an Event Notification:
- Event types: Object Create (Put)
- Destination: Queue
- Queue:
video-processing-queue
Alternatively, use Wrangler:
wrangler r2 bucket notification create your-source-bucket \
--event-type object-create \
--queue video-processing-queuewrangler deploywrangler deploy --env preview-
Upload a video file to your R2 bucket:
wrangler r2 object put your-source-bucket/video.mp4 --file ./video.mp4
-
The system will automatically:
- Detect the new file via R2 event notification
- Generate a presigned URL for the file
- Create a Stream video asset using the presigned URL
- Store the Stream URL mapping in KV
-
Retrieve Stream URLs:
wrangler kv key get "video.mp4" --binding STREAM_URLS
| Variable | Description | Required |
|---|---|---|
R2_SOURCE_BUCKET |
R2 bucket binding for source videos | ✅ |
R2_ACCESS_KEY_ID |
R2 API access key ID | ✅ |
R2_SECRET_ACCESS_KEY |
R2 API secret access key | ✅ |
CLOUDFLARE_ACCOUNT_ID |
Your Cloudflare account ID | ✅ |
CLOUDFLARE_API_TOKEN |
API token with Stream permissions | ✅ |
ALLOWED_ORIGINS |
Only allow specific origins to have stream access. Seperated by comma. Example: "sample.com,stream.sample.com" | ✅ |
pnpm run devpnpm testpnpm run cf-typegen
{ "$schema": "node_modules/wrangler/config-schema.json", "name": "auto-stream", "main": "src/index.ts", "compatibility_date": "2025-07-09", "observability": { "enabled": true }, "workers_dev": false, "r2_buckets": [ { "binding": "VIDEO", "bucket_name": "video" } ], "kv_namespaces": [ { "binding": "STREAM_URLS", "id": "<KV_ID>" } ] }