ffmpeg on Vercel은 배포 단계에서 깨져요 — 깨지지 않는 API를 호출하세요.
로컬에서는 잘 됐는데 배포하자마자 깨졌나요? 문제는 코드가 아니라 런타임이에요. Vercel 함수에서 Fotovid를 호출하세요: source URL을 보내면 Fotovid가 렌더링된 미디어를 돌려줘요.
// 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 });
}ffmpeg가 Vercel에서 깨지는 이유
Vercel은 앱을 실행하기엔 훌륭한 곳이지만 ffmpeg를 실행하기엔 최악의 환경이에요. Node 서버리스 함수는 압축 해제 시 번들 용량을 250MB로 제한하는데, 여러분 코드의 용량은 셈에 넣지도 못한 채, ffmpeg와 코덱만으로 이미 이 한도를 넘어서요. 용량 제한을 피하려고 Edge 런타임으로 바꾸면 child_process 자체가 없어져서 바이너리를 실행할 방법이 아예 사라져요. 어찌어찌 빌드가 통과하더라도 함수 타임아웃(Hobby 요금제는 10초, Pro는 제한적으로 설정 가능)이 제대로 된 인코딩을 중간에 끊어버려요. ffmpeg-static과 fluent-ffmpeg가 로컬에서는 통과하고 배포하면 실패하는 이유가 바로 이거예요.
- 압축 해제 시 250MB인 번들 용량 제한: ffmpeg와 코덱이 Node 서버리스 번들에 다 들어가지 않아요
- Edge 런타임에는 Node API도 child_process도 없어서 바이너리를 실행할 수 없어요
- 함수 타임아웃(Hobby 10초, Pro는 제한적)이 긴 인코딩을 중간에 끊어버려요
- ffmpeg-static과 fluent-ffmpeg는 로컬에서는 동작하지만 배포하는 순간 깨져요
Vercel에서 ffmpeg를 실행하려는 시도들
Fotovid 이전에는 이런 선택지들뿐이었어요 — 하나같이 직접 떠안고 싶지 않은 일이죠.
| Option | What it costs you | Verdict |
|---|---|---|
| Vercel 함수에 ffmpeg 번들링하기 | 250MB 번들 용량 제한을 넘어서고, Edge에는 child_process도 없어요 | |
| 컨테이너나 VM을 직접 호스팅하기 | 상시 운영 비용에 패치, 스케일링, 모니터링까지 떠안아야 해요 | |
| 잡 큐 + 워커 운영하기 | 새 인프라가 필요해요: 큐, 워커, 재시도, 데드레터 처리까지 | |
| 브라우저에서 트랜스코딩하기 (WASM) | 느리고 메모리를 많이 잡아먹고 모바일에서 죽어요 | |
| Fotovid API 호출하기 | HTTPS 요청 한 번이면 끝 — 실행할 것도, 패키징할 것도, 스케일링할 것도 없어요 |
세 단계로 끝내는 첫 호출
- 1무료 API 키 발급받기
카드 등록 없이 가입하고 키를 발급받으세요. p6_<key_id>:<secret> 형식의 토큰을 받으면 이걸 Bearer 인증 헤더로 전달하면 돼요. Vercel 프로젝트의 환경 변수에 넣어두면 함수가 런타임에 읽어올 수 있어요.
- 2watermark 엔드포인트로 영상을 POST하기
Vercel 함수에서 https://api.fotovid.co로 POST /v1/video/watermark 요청을 표준 envelope 형식으로 보내세요: 입력 영상을 가리키는 source_url과, 오버레이(이미지 또는 텍스트 워터마크, 위치, 불투명도, 크기)를 설명하는 params 객체를 담으면 돼요. 함수 안에서 바이너리도, 번들도, 인코딩도 실행되지 않아요. ffmpeg 작업은 Fotovid가 자체 인프라에서 처리하니 타임아웃은 애초에 신경 쓸 필요가 없어요.
- 3반환된 호스팅 URL 사용하기
응답은 id, type, 완성된 영상의 fotovid 호스팅 url, expires_at을 담은 플랫 JSON으로 돌아와요. 이 파일을 직접 저장해두거나 URL을 그대로 프론트엔드에 넘기면 돼요. 같은 envelope가 trim, extract-audio, extract-cover, probe 등 API의 나머지 기능에도 그대로 적용돼요.
