FFmpeg jobs for serverless

Run FFmpeg on Vercel

This is the whole integration. One HTTP request offloads the command and returns right away, so your function stays tiny and runs on Node or Edge.

FFmpeg API guide Updated June 2026
// app/api/transcode/route.ts
import { createClient } from "@rendobar/sdk";
export const runtime = "nodejs"; // or "edge", it's a plain fetch
const rb = createClient({ apiKey: process.env.RENDOBAR_API_KEY! });
export async function POST(req: Request) {
const { videoUrl } = await req.json();
// Offload the command, return right away.
const job = await rb.jobs.create({
type: "ffmpeg",
params: { command: `ffmpeg -i ${videoUrl} -c:v libx264 out.mp4` },
});
return Response.json({ jobId: job.id });
}

Why the local approach breaks

On the Node runtime the binary fits. It is about 76 MB against a 250 MB bundle cap, and Large Functions raises that ceiling to 5 GB. What breaks is everything after it deploys. Your function holds open for the whole transcode, and Vercel caps request and response bodies at 4.5 MB, so the video cannot travel through the function itself.

On the Edge runtime it isn't a size problem at all. There is no child_process to spawn a binary with, and the code cap is 1 MB gzipped on Hobby against 28 MB for a compressed FFmpeg build. The offload version is the snippet at the top of this page.

Bundle the binary Breaks on Vercel
// app/api/transcode/route.ts
import ffmpegPath from "ffmpeg-static";
import { spawn } from "node:child_process";
// Around 76 MB of binary. That fits the 250 MB Node cap.
// But on the Edge runtime this file won't even deploy:
// there is no child_process to spawn a binary with.
export const runtime = "nodejs"; // Edge is off the table
export async function POST(req: Request) {
const { videoUrl } = await req.json();
return new Promise((resolve) => {
const proc = spawn(ffmpegPath!, [
"-i", videoUrl, "-c:v", "libx264", "-crf", "23", "/tmp/out.mp4",
]);
// The function holds open for the whole transcode and can hit
// the 300s wall (800s on Pro with maxDuration) on long jobs.
proc.on("close", () => resolve(Response.json({ ok: true })));
});
}

What happens after you submit

  1. 01

    Submit the command

    Your Vercel function calls rb.jobs.create with type "ffmpeg" and your command string. The call is a single HTTPS request, so it returns in milliseconds and your function stays small.

  2. 02

    A sandboxed container runs it

    Rendobar runs the exact FFmpeg command in an isolated container built for media work. Full codecs, full CPU, no 250 MB bundle, no Lambda layer to attach.

  3. 03

    The result is stored, a URL comes back

    When the command finishes, the output is stored and the job result carries its URL. Read it from the webhook in the next step, or poll GET /jobs/{id}.

  4. 04

    A webhook fires

    Rendobar POSTs the finished job to the endpoint you registered. Your function never had to wait, so it never hit the 300s timeout (or the 800s Pro ceiling).

Ways to run FFmpeg on Vercel, compared

ApproachWorks on Vercel?Why
ffmpeg-static on the Node runtime YesFits at 76 MB, but holds the function open
ffmpeg-static on the Edge runtime NoNo child_process, and a 1 MB to 4 MB code cap
ffmpeg.wasm in the function NoRuns, but slow and memory / time limited
Custom Lambda layer NoYou don't control Vercel's Lambda
Rendobar API (offload) YesOne fetch, any runtime, nothing to bundle

Frequently asked questions

Can I run FFmpeg inside a Vercel Function?

On the Node runtime, yes. The ffmpeg-static binary is about 76 MB against a 250 MB bundle cap, and Large Functions raises that ceiling to 5 GB. Two things still bite. Your function stays open for the whole transcode, and Vercel caps request and response bodies at 4.5 MB, so the video itself cannot travel through it. On the Edge runtime it is not possible at all: there is no child_process to spawn a binary, and the code cap is 1 MB gzipped on Hobby.

Does this work with the Edge runtime?

Yes. The call is a plain HTTPS fetch, so it runs on both Node and Edge. Rendobar runs the FFmpeg command in a sandboxed container and returns the output URL on a webhook.

My function times out before the video is done. How do I get the result?

Don't keep the function open. Register a webhook endpoint once (rb.webhooks.create) and Rendobar POSTs each finished job to it. You can also poll GET /jobs/{id} or await rb.jobs.wait(id) for short jobs.

I set maxDuration in vercel.json. Doesn't that fix it?

It raises the ceiling to 800s on Pro (Hobby stays at 300s), but a long transcode can still blow past it, and you pay for every second the function stays open. Offloading returns in milliseconds no matter how long the video runs.

What's the largest command I can send?

Any single FFmpeg command. You pass it as params.command on an ffmpeg job, exactly the string you'd type in a terminal. Inputs are fetched by URL or uploaded as assets, up to 500 MB on the Free plan and 10 GB on Pro, with up to 8 GB processed per job.

What does it cost?

Jobs are billed by compute time. Every account begins with $5 in free credits and no credit card, so you can run a real transcode before paying anything.

Ship FFmpeg on Vercel today

$5 free on signup. No credit card. No bundle to blow.