Video processing shouldn't require child_process
The typical Node.js approach to FFmpeg is child_process.spawn(). You shell out to a binary, parse stderr for progress, handle exit codes, and hope the binary exists on your deployment target.
This works locally. It breaks in production when the FFmpeg binary isn't installed, isn't the right version, or doesn't support the codec you need. If you've compared self-hosted vs cloud FFmpeg, you know the tradeoffs.
Here's the alternative: fetch(). Ten lines, no binary dependency.
It works everywhere Node.js runs — no binary to bundle, no codec compatibility issues.
Setup
Zero dependencies required. Node.js 18+ has built-in fetch. For older versions, use node-fetch.
Every example below uses this runFFmpeg function.
Convert formats
MOV to MP4:
MP4 to WebM:
Resize for social platforms
TikTok (1080x1920):
YouTube Shorts (1080x1920, same dimensions):
720p for general web use:
Extract audio
To MP3:
Generate thumbnails
For advanced frame extraction — keyframes, scene detection, and batch processing — see the FFmpeg frame extraction guide.
Single frame at 5 seconds:
Trim video
For keyframe-accurate trimming, batch operations, and the trim filter, see the dedicated trim guide.
30 seconds starting at 1:00:
Add watermark
This is a basic fixed-position overlay. For responsive scaling with scale2ref, semi-transparent logos, text overlays, and moving watermarks, the FFmpeg watermark guide covers it all.
Using webhooks instead of polling
Polling works for scripts and CLIs. For web applications, webhooks are better. Configure a webhook URL in your RenderIO dashboard, then submit without polling:
Your server just reacts to events instead of burning cycles polling. For a full walkthrough of the submit-poll-download flow, see the REST API tutorial.
Batch processing
Process multiple videos concurrently with Promise.all:
Promise.allSettled ensures one failure doesn't cancel the rest. Each video processes in its own container. If you're doing this at scale for social media, the batch video processing guide covers the full pipeline.
Express.js integration
A complete Express endpoint that accepts video uploads and returns processed versions:
Four operations behind a single endpoint — compress, thumbnail, extract audio, resize. You could add more by extending the commands object.
TypeScript types
If you're using TypeScript, here are the types for the API responses:
FAQ
Does this work with Bun or Deno?
Yes. Both Bun and Deno support fetch natively, so the code works without changes. The only thing to adjust is how you load environment variables for the API key.
Can I use this with Next.js API routes?
Absolutely. The runFFmpeg function works in any server-side Node.js context. In Next.js, call it from an API route or a Server Action — just don't call it from client-side code since that would expose your API key.
How do I handle large files that take minutes to process?
Use webhooks instead of polling. Submit the job, store the command_id in your database, and let RenderIO POST the result to your webhook endpoint when it's done. The webhook section above shows the Express setup.
What's the maximum concurrent requests?
It depends on your plan. The API processes each job in an isolated container, so there's no shared resource bottleneck. For heavy batch workloads, you might want to limit your Promise.all concurrency to avoid hitting rate limits.
Can I use this with the Node.js FFmpeg cheat sheet commands?
Yes — every command from the FFmpeg cheat sheet works. Replace local file paths with URL placeholders ({input}, {output}) and pass them through runFFmpeg. For Node.js-specific examples of concatenating multiple clips via the API, the FFmpeg concat guide includes a complete concatVideos() function with dynamic filter_complex generation.
Get started
For a quick reference of common FFmpeg commands you can use with this setup, check the curl examples. The same commands work in both curl and Node.js.
The Starter plan at $9/mo includes 500 commands. Get your API key to start building.