How to Render MP4s in Node.js Without FFmpeg
May 21, 2026 · By VideoFlowLearn how to generate high-quality MP4 videos directly in Node.js using VideoFlow and WebCodecs, eliminating the need for complex FFmpeg installations.
How to Render MP4s in Node.js Without FFmpeg
For years, programmatic video in Node.js has been synonymous with one thing: shell-scripting FFmpeg. Whether you were using a wrapper library or spawning child processes manually, the workflow was always the same—install a heavy binary, manage codec flags, and hope the string-concatenated command didn't break in production.
But as we move toward more modern, web-standard pipelines, that dependency is becoming an unnecessary bottleneck. In this guide, we'll look at how to render high-quality MP4s directly in Node.js using VideoFlow and WebCodecs, completely bypassing the need for a local FFmpeg installation.
Why Move Away from FFmpeg?
FFmpeg is a legendary tool, but it wasn't built for the modern cloud-native developer. When you're building a video automation platform or a SaaS that generates personalized content, FFmpeg introduces several friction points:
- Environment Bloat: Your Docker images grow by hundreds of megabytes just to include the binary.
- Platform Inconsistency: 'libx264' might behave differently on your Mac than on a Linux Lambda function.
- The Screenshot Bottleneck: Traditional programmatic video often involves taking thousands of individual screenshots (JPEGs) and piping them into FFmpeg's stdin, which is incredibly slow and CPU-intensive.

The Modern Alternative: WebCodecs + Playwright
VideoFlow takes a different approach. By using @videoflow/renderer-server, you can drive a headless Chromium instance via Playwright. Instead of taking screenshots, VideoFlow uses the WebCodecs API inside the browser to encode frames directly to an MP4 container.
This method is typically several times faster because it eliminates the per-frame screenshot round-trip. The frames stay in the browser's memory until the final MP4 is muxed and sent back to your Node process as a Buffer.
Step 1: Setting up the Project
First, install the core library and the server renderer:
npm install @videoflow/core @videoflow/renderer-server
npx playwright install chromium
Step 2: Building Your Video
Using the fluent VideoFlow builder API, we can compose a scene with just a few lines of TypeScript. Notice how we use normalized coordinates ([0.5, 0.5]) and em units to keep the design resolution-agnostic.
import VideoFlow from '@videoflow/core';
import '@videoflow/renderer-server'; // Registers the server-side renderer
const $ = new VideoFlow({
width: 1920,
height: 1080,
fps: 30,
backgroundColor: '#000000'
});
// Add a background image
const bg = $.addImage(
{ fit: 'cover', opacity: 0.8 },
{ source: 'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe' }
);
// Add a title with a transition
const title = $.addText(
{
text: 'NO FFMPEG REQUIRED',
fontSize: 8,
color: '#FF5A1F',
fontWeight: 800,
position: [0.5, 0.4]
},
{
transitionIn: { transition: 'blurResolve', duration: '800ms' }
}
);
$.wait('3s');
title.fadeOut('500ms');
Step 3: Rendering to a File
Now, we tell the renderer to produce our MP4. By default, VideoFlow uses the WebCodecs pipeline. You don't need to pass any special flags—it just works.
await $.renderVideo({
outputType: 'file',
output: './automated-video.mp4',
verbose: true
});

Deep Dive: How it Works Under the Hood
When you call renderVideo in a Node environment, the @videoflow/renderer-server package performs a few clever tricks:
- Shared Browser Instance: It maintains a shared Playwright browser instance to avoid the cold-start cost of launching Chromium for every render.
- In-Page Bundling: It bundles a small renderer script using
esbuildand injects it into the headless page. - Direct Buffer Handoff: The finished MP4 bytes are POSTed from the headless browser back to the Node process, where they are converted into a standard Buffer.
If you're building a high-scale SaaS video pipeline, this architecture allows you to scale horizontally without worrying about the underlying OS dependencies.
Conclusion
Rendering video in Node.js doesn't have to be a headache. By leveraging the power of WebCodecs and a portable JSON-based schema, VideoFlow makes it possible to generate cinematic content with zero FFmpeg baggage.
Whether you're migrating from Remotion to get a more flexible, Apache-2.0 licensed core, or you're simply tired of FFmpeg's complexity, the future of video-as-code is here.
Ready to try it out? Head over to the VideoFlow Playground to build your first scene in the browser, or check out our getting started guide to start building on the server. You can also explore the source code on GitHub.