How to Build a Production-Ready Video Rendering Pipeline with Node.js and BullMQ
May 21, 2026 · By VideoFlowLearn how to scale VideoFlow rendering using BullMQ and Node.js. Build a robust, distributed video rendering pipeline that handles high-concurrency workloads.
Building a video rendering pipeline that can handle hundreds of concurrent requests isn't just about how fast you can render a single frame. It’s about how you manage resources, handle failures, and scale your worker nodes without crashing your primary application server.
When you're automating video at scale—whether for personalized SaaS recaps or dynamic social media ads—you need a distributed architecture. In this guide, we’ll show you how to build a production-ready video rendering pipeline using VideoFlow, Node.js, and BullMQ.
Why a Queue Matters for Video Automation
Video rendering is a CPU and memory-intensive task. If you try to render a complex 1080p video directly inside your web request handler, you'll quickly block the event loop and exhaust your server's resources.
A robust video rendering pipeline solves this by:
- Decoupling the request from the execution.
- Isolating the rendering environment in worker nodes.
- Providing automatic retries and progress tracking.
By using BullMQ, we can create a resilient system where our main API simply emits a "render job" and a fleet of workers handles the heavy lifting.

Setting Up the VideoFlow Worker
First, let's look at the worker code. We'll use @videoflow/renderer-server because it runs in Node.js and leverages headless Chromium via Playwright for high-fidelity rendering.
import { Worker } from 'bullmq';
import VideoFlow from '@videoflow/core';
import '@videoflow/renderer-server';
const worker = new Worker('video-tasks', async (job) => {
const { videoData, outputKey } = job.data;
// 1. Reconstruct the VideoFlow instance from JSON
// In a real app, you might generate this dynamically from job.data
const $ = new VideoFlow({
width: 1920,
height: 1080,
fps: 30
});
$.addText({
text: `Hello, ${videoData.userName}`,
fontSize: 6,
color: '#FF5A1F',
position: [0.5, 0.5]
}).fadeIn('500ms');
$.wait('3s');
// 2. Render to a Buffer
// This uses the official @videoflow/renderer-server package
const buffer = await $.renderVideo({
outputType: 'buffer',
verbose: false
});
// 3. Upload to S3 or your storage provider
await uploadToS3(outputKey, buffer);
return { success: true, url: `https://cdn.example.com/${outputKey}` };
}, {
connection: { host: 'localhost', port: 6379 },
concurrency: 2 // Adjust based on your CPU/RAM
});
Managing Concurrency and Resources
One of the biggest challenges in a video rendering pipeline is resource management. Each instance of @videoflow/renderer-server launches a headless browser. While VideoFlow is highly optimized, multiple concurrent renders can still eat through RAM.

When configuring your workers, consider these three rules:
- Concurrency Limits: Start with a low concurrency (1-2) per worker and scale horizontally by adding more worker processes/containers rather than increasing concurrency on a single machine.
- Timeout Management: Video rendering can take time. Ensure your BullMQ jobs have a generous
lockDurationandtimeoutto prevent jobs from being marked as failed while they are still processing. - Graceful Shutdowns: Always call
closeSharedBrowser()from@videoflow/renderer-serverwhen your worker process receives a termination signal to ensure no zombie Chromium processes are left behind.
How VideoFlow Simplifies the Pipeline
VideoFlow was built from the ground up to be "pipeline-friendly." Unlike other tools that require a specific framework or a proprietary runtime, VideoFlow uses a portable VideoJSON format.
You can prototype your scenes in the VideoFlow Playground, export the JSON, and then feed that exact same JSON into your server-side workers. Because our official renderers produce byte-for-byte identical output, you never have to worry about a video looking different on your server than it did during development.
This portability is what makes it a superior choice for automated SaaS user recap videos and other high-volume automation tasks. You can even use the browser-based renderer to offload the rendering cost to the user's browser when a server-side queue isn't necessary.
Scaling to Thousands of Videos
As your needs grow, you can deploy your workers to serverless environments or container orchestration platforms like Kubernetes. Since @videoflow/renderer-server doesn't require FFmpeg by default (it uses a high-performance WebCodecs-based pipeline), your container images stay lean and easy to deploy.
Ready to start building? Check out our Getting Started guide or dive into the GitHub repository to see the source code for our renderers. Your production-ready video rendering pipeline is just a few lines of code away.