ffmpeg on Vercel breaks at deploy — call an API that doesn't.
It worked on localhost, then broke the moment you deployed. That's not your code, it's the runtime. Point your Vercel function at Fotovid: it sends a source URL, Fotovid returns the rendered media.
// app/api/watermark/route.ts
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const { videoUrl, logoUrl } = await req.json();
const res = await fetch("https://api.fotovid.co/v1/video/watermark", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.FOTOVID_API_KEY!}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
source_url: videoUrl,
params: { type: "image", watermark_image_url: logoUrl, position: "bottom-right" },
}),
});
const { url } = await res.json();
return NextResponse.json({ url });
}Why ffmpeg breaks on Vercel
Vercel is a great place to run your app and a hostile one to run ffmpeg. Node serverless functions cap the unzipped bundle at 250MB, and ffmpeg plus its codecs blow past that before your own code is counted. Switch to the Edge runtime to dodge the size limit and you lose child_process entirely, so there is no way to spawn a binary. Even when a build sneaks through, the function timeout (10s on Hobby, bounded on Pro) kills any real encode partway. ffmpeg-static and fluent-ffmpeg pass locally and fail on deploy for exactly these reasons.
- 250MB unzipped function cap: ffmpeg plus codecs don't fit in a Node serverless bundle
- Edge runtime has no Node APIs and no child_process, so you can't spawn a binary
- Function timeouts (10s Hobby, bounded on Pro) cut off long encodes mid-run
- ffmpeg-static and fluent-ffmpeg work on localhost and break the moment you deploy
Ways teams try to run ffmpeg on Vercel
Before Fotovid these were the options — each one is work you'd rather not own.
| Option | What it costs you | Verdict |
|---|---|---|
| Bundle ffmpeg into your Vercel function | Blows past the 250MB function limit; Edge has no child_process | |
| Self-host a container or VM | Always-on cost plus patching, scaling, and monitoring | |
| Run a job queue + worker | New infra: a queue, workers, retries, dead-letter handling | |
| Transcode in the browser (WASM) | Slow, memory-hungry, and crashes on mobile | |
| Call the Fotovid API | One HTTPS request; nothing to run, package, or scale |
Your first call in three steps
- 1Grab a free API key
Sign up and create a key, no card required. You get a token in the form p6_<key_id>:<secret> that you pass as a Bearer authorization header. Drop it into your Vercel project's environment variables so your function can read it at runtime.
- 2POST your video to the watermark endpoint
From your Vercel function, call POST /v1/video/watermark on https://api.fotovid.co with the standard envelope: a source_url pointing at your input video, plus a params object describing the overlay (an image or text watermark, its position, opacity, and scale). No binary, no bundle, no encode running inside your function. Fotovid does the ffmpeg work on its own infrastructure, so your timeout never enters the picture.
- 3Use the returned hosted URL
The response comes back as flat JSON with an id, type, a fotovid-hosted url for the finished video, and an expires_at. Store your own copy of that file, or hand the URL straight to your frontend. Same envelope works for the rest of the API: trim, extract-audio, extract-cover, probe, and more.
Frequently asked questions
Ship it with one API call
Grab a free key and make your first call in under five minutes.
