ffmpeg trên Vercel

ffmpeg trên Vercel gãy ngay lúc deploy — hãy gọi một API không gãy.

Nó chạy tốt trên localhost, rồi gãy ngay khi Bạn deploy. Đó không phải lỗi code của Bạn, mà là do runtime. Trỏ Vercel function của Bạn đến Fotovid: gửi một source URL, Fotovid trả về media đã render.

// 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 });
}

Vì sao ffmpeg gãy trên Vercel

Vercel là nơi tuyệt vời để chạy app của Bạn nhưng lại khắc nghiệt với ffmpeg. Node serverless function giới hạn bundle chưa nén ở mức 250MB, và ffmpeg cùng các codec của nó đã vượt quá giới hạn này trước khi tính đến code của riêng Bạn. Nếu chuyển sang Edge runtime để né giới hạn dung lượng, Bạn sẽ mất hoàn toàn child_process — nghĩa là không có cách nào spawn một binary. Ngay cả khi một bản build lọt qua được, function timeout (10s trên Hobby, có giới hạn trên Pro) cũng sẽ giết bất kỳ encode thực sự nào giữa chừng. ffmpeg-static và fluent-ffmpeg chạy được ở local nhưng gãy ngay khi deploy, chính vì những lý do này.

  • Giới hạn 250MB cho function chưa nén: ffmpeg và các codec không vừa trong một bundle Node serverless
  • Edge runtime không có Node API và không có child_process, nên Bạn không thể spawn một binary
  • Function timeout (10s trên Hobby, có giới hạn trên Pro) cắt ngang các encode dài giữa chừng
  • ffmpeg-static và fluent-ffmpeg chạy tốt trên localhost nhưng gãy ngay khi Bạn deploy

Những cách các team từng thử để chạy ffmpeg trên Vercel

Trước khi có Fotovid, đây là các lựa chọn — mỗi cái đều là việc mà Bạn chẳng muốn ôm vào người.

OptionWhat it costs youVerdict
Đóng gói ffmpeg vào Vercel function của BạnVượt quá giới hạn 250MB của function; Edge không có child_process
Tự host một container hoặc VMChi phí chạy liên tục cộng thêm việc vá lỗi, scale và giám sát
Chạy một job queue + workerHạ tầng mới: một queue, các worker, retry, xử lý dead-letter
Transcode ngay trên trình duyệt (WASM)Chậm, ngốn nhiều bộ nhớ, và crash trên mobile
Gọi Fotovid APIMột request HTTPS duy nhất; không có gì phải chạy, đóng gói hay scale
How it works

Lệnh gọi đầu tiên của Bạn trong ba bước

  1. 1
    Lấy một API key miễn phí

    Đăng ký và tạo một key, không cần thẻ. Bạn nhận được một token theo dạng p6_<key_id>:<secret> để truyền vào header authorization dạng Bearer. Thêm nó vào environment variables của Vercel project để function của Bạn đọc được lúc runtime.

  2. 2
    POST video của Bạn tới endpoint watermark

    Từ Vercel function của Bạn, gọi POST /v1/video/watermark trên https://api.fotovid.co với envelope chuẩn: một source_url trỏ tới video đầu vào của Bạn, cùng một params object mô tả overlay (watermark dạng ảnh hoặc text, vị trí, độ trong suốt và tỷ lệ). Không cần binary, không cần bundle, không có encode nào chạy bên trong function của Bạn. Fotovid xử lý phần ffmpeg trên hạ tầng riêng của nó, nên timeout của Bạn không bao giờ là vấn đề.

  3. 3
    Dùng URL đã được host trả về

    Response trả về là JSON phẳng gồm một id, type, một url được host trên Fotovid cho video hoàn chỉnh, và một expires_at. Bạn có thể lưu lại bản sao của file đó, hoặc đưa thẳng URL cho frontend của mình. Cùng một envelope này áp dụng cho phần còn lại của API: trim, extract-audio, extract-cover, probe, và nhiều hơn nữa.

Câu hỏi thường gặp

Triển khai chỉ với một lệnh gọi API

Lấy một key miễn phí và thực hiện lệnh gọi đầu tiên trong chưa đầy năm phút.