Amar — a cinematic HLS pipeline for a working video editor.
FFmpeg → BullMQ → Cloudflare R2 → adaptive streaming, and the three things I would change now.

§01The problem
Dropping raw 4K MP4s onto a page is a great way to make a portfolio feel broken — multi-second loads, no quality adaptation, and a browser that chokes when several videos share a screen. A video editor's site failing to play video is the worst possible first impression.
The real requirement was adaptive streaming: serve the right quality for each viewer's connection, start fast, and let several players coexist without fighting over bandwidth or memory.
§02The pipeline
Upload bypasses the server, a queue does the heavy lifting, and the player just reads a playlist. Each stage is independent so a failure in one does not corrupt the others.
§03Three decisions worth defending
Direct-to-R2 uploads via signed URLs
Large source files never touch the app server — the client uploads straight to R2 with a pre-signed URL, and only the completion event hits the backend. The server stays cheap and never streams gigabytes.
A queue, not a request, for transcoding
Transcoding is minutes of work; an HTTP request is the wrong place for it. BullMQ decouples “upload finished” from “encode done”, with retries and visibility into the job state.
Context-driven multi-instance players
Several HLS players on one page need to share state — only one plays at a time, others pause. A small React context coordinates them instead of each player reinventing its own controls.
§04Three things I would change
Move transcoding off the main process
I ran FFmpeg inside the main Hono process — fine at low traffic, but a heavy encode blocks the event loop. Next time: a dedicated worker service on a separate machine.
Stream job progress over SSE
The upload UI shows a spinner until transcoding finishes. A progress bar streamed via server-sent events would be far better UX for long encodes — the data is already in BullMQ.
Consider Cloudflare Stream
I built the pipeline from scratch to learn it end to end. For a production client deadline, Cloudflare Stream handles transcode + storage + CDN in one service — I would use it and spend the saved time on the UI.
“Building the pipeline took a week. Making it reliable took three more — and that ratio is the whole job.”— Parm, on AmarV4