If you have ever tried to push real video files through n8n nodes, you already know the ending: memory pressure, stalled executions, and a workflow that dies exactly when it matters. n8n is a brilliant orchestrator — and a terrible byte-mover.
The rule: n8n handles logic, a microservice handles bytes
My YouTube automation pipeline publishes 6 Shorts and 2 long-form videos every day. n8n never touches a video file. It passes file paths and job references to a small Flask service in Docker (running on a free-tier ARM64 box) that owns every FFmpeg operation.
# The contract is deliberately boring:
POST /render
{
"job_id": "short-2026-07-06-04",
"source": "/data/raw/ep-114.mp4",
"ops": ["reframe-9x16", "karaoke-subs", "kenburns-intro", "audio-mix"]
}
# n8n polls /status/{job_id} — bytes never cross the webhook boundary.What lives inside the microservice
- Scripted FFmpeg filter graphs: Ken Burns pans, karaoke subtitles, audio ducking, 9:16 reframes — no editor ever opens.
- A job queue with idempotent job IDs, so a retried webhook cannot double-render.
- Disk hygiene: rendered artifacts are cleaned on a schedule, because the disk WILL fill (ask me how I know).
Why not just use bigger n8n instances?
Because the failure mode does not scale away — it just moves the cliff. Separating orchestration from rendering means each side fails independently and recovers independently. The pipeline has run daily since 2024 at $0/month infrastructure cost. That number is the entire business case.
from the system this note is based onYouTube Automation Pipeline — full case study →