Lambda FFmpeg & Serverless: Stolpersteine und was wirklich hilft
Warum FFmpeg auf AWS Lambda, Vercel und Cloudflare Workers schmerzhaft wird — Binary-Größe, Timeouts, Memory, Cold Starts — und welche Alternativen sich in der Praxis lohnen.

Serverless-Plattformen versprechen unendliche Skalierung und null Ops. Wenn du also Video verarbeiten musst — einen Clip schneiden, ein Thumbnail erzeugen, einen Upload transkodieren — denkst du naheliegend: einfach FFmpeg auf Lambda laufen lassen. Wie schwer kann das sein?
Sehr schwer, wie sich herausstellt. Dieser Guide geht durch die echten Probleme beim Betrieb von FFmpeg auf Serverless, die üblichen Workarounds, wo sie an die Wand fahren, und wann eine dedizierte API mehr Sinn ergibt.
Warum FFmpeg auf Serverless nicht passt
1. Binary-Größe — 70 MB+, bevor du überhaupt anfängst
Eine statisch kompilierte FFmpeg-Binary mit gängigen Codecs (H.264, H.265, VP9, AAC, Opus) wiegt 70-100 MB. Pack libass (Untertitel) oder libfdk-aac (hochwertiges AAC) dazu, und du landest bei 120 MB+.
Die Plattform-Limits machen das schmerzhaft:
| Plattform | Deployment-Größe | Beinhaltet |
|---|---|---|
| AWS Lambda (zip) | 50 MB (250 MB unzipped) | Code + Dependencies + Binary |
| AWS Lambda (Container) | 10 GB | Mehr Platz, aber langsamerer Cold Start |
| Vercel Serverless Functions | 50 MB | Komprimiert |
| Cloudflare Workers | 10 MB (mit Paid Plan) | Kein nativer Binary-Support |
| Google Cloud Functions | 500 MB (Source) | Großzügiger |
Auf AWS Lambda mit Zip-Deployment frisst die FFmpeg-Binary allein den Großteil deiner 50 MB. Dein eigener Anwendungscode konkurriert um den Rest.
2. Execution-Timeout — maximal 15 Minuten
AWS Lambdas Maximum sind 15 Minuten. Andere Plattformen sind noch strenger:
| Plattform | Max. Timeout |
|---|---|
| AWS Lambda | 15 min |
| Google Cloud Functions | 9 min (60 min 2nd gen) |
| Vercel Serverless | 5 min (Pro), 60s (Hobby) |
| Cloudflare Workers | 30s (Standard), 15 min (Workflows) |
Ein 15-Minuten-Timeout klingt großzügig — bis du dir anschaust, was FFmpeg-Verarbeitung tatsächlich braucht:
| Aufgabe | 1080p, 10-min-Video | Zeit auf 2 vCPU |
|---|---|---|
| Thumbnail extrahieren | 1 Frame | < 1 Sek |
| Audio extrahieren | Stream Copy | < 5 Sek |
| Transcode nach H.264 | CRF 23, medium | 8-12 min |
| Transcode nach H.265 | CRF 28, medium | 15-25 min |
| Hardcoded Subtitles | Re-Encode | 10-15 min |
| Transcode nach VP9 | CRF 30 | 20-40 min |
Einfache Aufgaben wie Thumbnails und Audio-Extraktion passen locker rein. Aber jedes echte Transcoding von Videos länger als ein paar Minuten knallt gegen Lambdas Timeout — oder gefährlich nah dran. Wie Encoding-Settings die Verarbeitungszeit beeinflussen, steht in unseren Compression Best Practices.
3. Memory-Limits — kein Platz für große Files
Videoverarbeitung ist hungrig nach RAM. FFmpeg puffert Input und Output, und komplexe Filter halten mehrere Frames gleichzeitig im Speicher.
| Plattform | Max. Memory |
|---|---|
| AWS Lambda | 10 GB |
| Google Cloud Functions | 32 GB (2nd gen) |
| Vercel Serverless | 3 GB |
| Cloudflare Workers | 128 MB |
AWS Lambda mit 10 GB klingt fein — aber Memory wirkt direkt auf die Kosten. Lambda berechnet nach GB-Sekunden. Eine Function, die 10 Minuten 4 GB nutzt, kostet 40x mehr als eine, die 15 Sekunden 256 MB nutzt.
Realistische Memory-Werte für FFmpeg-Aufgaben:
| Aufgabe | Typischer RAM |
|---|---|
| Thumbnail extrahieren | 100-200 MB |
| Audio extrahieren | 50-150 MB |
| 1080p H.264 Transcode | 500 MB - 1.5 GB |
| 4K H.264 Transcode | 2-4 GB |
| Komplexe Filter Chains | 1-4 GB |
4. Kein GPU Acceleration
Hardware-beschleunigtes Encoding (NVENC, QSV, VAML) macht Videoverarbeitung dramatisch schneller — 5-10x schneller für H.264/H.265. Aber Serverless-Plattformen geben keinen GPU-Zugriff.
Heißt: Du sitzt auf CPU-Encoding fest, und das ist:
- 5-10x langsamer als GPU-Encoding
- Pro Video teurer im großen Maßstab
- Wahrscheinlicher, ins Timeout zu rennen
5. Cold-Start-Strafe
Jeder Cold Start lädt die FFmpeg-Binary in die Execution Environment. Eine 70 MB+ Binary haut 1-3 Sekunden Cold-Start-Latenz oben drauf, zusätzlich zur Plattform-eigenen Initialisierung.
Bei container-basiertem Lambda (nötig für größere Binaries) können Cold Starts 5-15 Sekunden erreichen.
6. Begrenztes Ephemeral Storage
Lambda gibt dir /tmp mit 512 MB by default (gegen Aufpreis bis 10 GB konfigurierbar). Videodateien sind groß — ein 10-minütiges 1080p-Video sind 500 MB-1 GB. Du brauchst Platz für Input und Output:
Input file: 500 MB
Output file: 300 MB
FFmpeg temp: 200 MB
─────────────────
Total: 1 GB ← exceeds default /tmp
7. Keine persistenten Prozesse
FFmpeg profitiert oft von langlebigen Prozessen — Binary warm halten, Decode-Caches behalten, Connections wiederverwenden. Serverless-Functions sind stateless und ephemer. Jeder Aufruf fängt von vorn an.
Übliche Workarounds
Trotz dieser Probleme betreiben Teams FFmpeg auf Serverless. Die häufigsten Ansätze:
Lambda Layers
Mit AWS Lambda Layers kannst du FFmpeg getrennt vom Anwendungscode paketieren:
# Download a static FFmpeg build
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
tar xf ffmpeg-release-amd64-static.tar.xz
# Create Lambda layer structure
mkdir -p ffmpeg-layer/bin
cp ffmpeg-*-amd64-static/ffmpeg ffmpeg-layer/bin/
cd ffmpeg-layer && zip -r ../ffmpeg-layer.zip .
Dann in der Lambda-Function:
const { execSync } = require('child_process');
exports.handler = async (event) => {
// FFmpeg binary from layer is at /opt/bin/ffmpeg
const result = execSync(
'/opt/bin/ffmpeg -i /tmp/input.mp4 -vf "scale=-2:720" -crf 23 /tmp/output.mp4',
{ timeout: 300000 }
);
return { statusCode: 200 };
};
Limits:
- Layer-Größe zählt weiter aufs 250-MB-unzipped-Limit
- Du musst FFmpeg auf die Codecs reduzieren, die du wirklich brauchst
- Den eigenen FFmpeg-Build zu pflegen ist ein dauerhafter Aufwand
Docker Container Images
Lambda unterstützt Container Images bis 10 GB, was deutlich mehr Luft gibt:
FROM public.ecr.aws/lambda/nodejs:20
# Install FFmpeg
RUN yum install -y tar xz && \
curl -L https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz | \
tar xJ --strip-components=1 -C /usr/local/bin/ --wildcards '*/ffmpeg' '*/ffprobe'
COPY index.mjs ${LAMBDA_TASK_ROOT}/
CMD ["index.handler"]
Limits:
- Cold Starts werden deutlich länger (5-15 Sekunden)
- Größere Images bedeuten höhere ECR-Storage-Kosten
- Du sitzt weiter mit dem 15-Minuten-Timeout und ohne GPU da
ffmpeg.wasm — FFmpeg im Browser/Edge
ffmpeg.wasm kompiliert FFmpeg nach WebAssembly, sodass es in Browsern und Edge-Runtimes läuft:
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { fetchFile } from '@ffmpeg/util';
const ffmpeg = new FFmpeg();
await ffmpeg.load();
await ffmpeg.writeFile('input.mp4', await fetchFile(videoUrl));
await ffmpeg.exec(['-i', 'input.mp4', '-vf', 'scale=-2:720', 'output.mp4']);
const data = await ffmpeg.readFile('output.mp4');
Limits:
- 3-10x langsamer als natives FFmpeg
- Eingeschränkter Codec-Support (kein H.265, begrenzte Filter)
- Memory-limitiert in Browser-Umgebungen
- Kann keine Files größer als ein paar hundert MB
- Single-Threaded in den meisten Umgebungen
Chunked Processing
Große Videos in Stücke teilen, parallel verarbeiten, dann mergen:
# Split into 2-minute segments
ffmpeg -i input.mp4 -c copy -segment_time 120 -f segment -reset_timestamps 1 chunk_%03d.mp4
// Process chunks in parallel Lambda invocations
const chunks = ['chunk_000.mp4', 'chunk_001.mp4', 'chunk_002.mp4'];
const results = await Promise.all(
chunks.map(chunk => lambda.invoke({
FunctionName: 'process-chunk',
Payload: JSON.stringify({ chunk })
}).promise())
);
// Merge results
// (requires another Lambda invocation)
Limits:
- Aufwendige Orchestrierung (Step Functions, SQS usw.)
- Nicht alle Operationen lassen sich chunken (z. B. Subtitle-Timing über Chunks hinweg)
- Der Merge-Step kostet Latenz und kann Artefakte an Chunk-Grenzen erzeugen
- Gesamtkosten oft höher als ein einzelner Long-Running-Prozess
Stripped FFmpeg Builds
Kompiliere FFmpeg nur mit den Codecs, die du brauchst, um die Binary kleiner zu machen:
./configure \
--disable-everything \
--enable-decoder=h264,aac,mp3 \
--enable-encoder=libx264,aac \
--enable-muxer=mp4,mp3 \
--enable-demuxer=mov,mp4,mp3 \
--enable-protocol=file,pipe \
--enable-filter=scale,overlay \
--enable-gpl --enable-libx264
So kommst du auf 15-25 MB — verlierst aber Funktionalität. Brauchst du nächsten Monat VP9? Neu bauen.
Benchmark: Lambda vs. dedizierter Server
Damit du den Abstand siehst, hier Benchmarks für ein 5-Minuten-1080p-Video:
| Aufgabe | Lambda (3 GB, arm64) | EC2 c6g.large (2 vCPU) | EC2 g5.xlarge (GPU) |
|---|---|---|---|
| Thumbnail | 0.8s | 0.5s | 0.3s |
| Audio extract | 2s | 1.5s | 1.5s |
| H.264 CRF 23 | 4.5 min | 3.2 min | 25s |
| H.265 CRF 28 | 9 min | 7 min | 35s |
| VP9 CRF 30 | 12 min | 9 min | N/A |
Kostenvergleich für 1000 H.264-Transcodes (jeweils 5-min 1080p-Video):
| Ansatz | Zeit pro Video | Kosten pro Video | Gesamtkosten |
|---|---|---|---|
| Lambda (3 GB) | 4.5 min | ~$0.022 | ~$22 |
| EC2 c6g.large (reserved) | 3.2 min | ~$0.004 | ~$4 |
| EC2 g5.xlarge (GPU) | 25s | ~$0.008 | ~$8 |
Lambda ist für anhaltende Workloads ungefähr 5x teurer als eine Reserved EC2 Instance — und verliert seinen Kostenvorteil, sobald du mehr als eine Handvoll Videos pro Stunde verarbeitest.
Wann Serverless FFmpeg trotzdem Sinn ergibt
Trotz aller Probleme gibt es legitime Use Cases:
- Thumbnail-Generierung — Schnell, wenig Memory, gut innerhalb der Limits
- Audio-Extraktion mit Stream Copy — Quasi sofort, minimale Ressourcen
- Kurze Videoclips (< 30 Sekunden) — Schnelles Transcoding, das nicht ins Timeout läuft
- Metadaten-Extraktion — ffprobe läuft in Millisekunden
- Sporadischer, unvorhersehbarer Traffic — Wenn stundenlang gar kein Request kommt
# These tasks work well on Lambda
ffmpeg -i input.mp4 -ss 00:00:05 -frames:v 1 thumbnail.jpg # < 1s
ffmpeg -i input.mp4 -vn -c:a copy audio.aac # < 2s
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4 # < 1s
Wann lieber eine dedizierte API
Serverless versagt, wenn du brauchst:
- Transcoding von Videos länger als 2-3 Minuten — Timeout-Risiko
- H.265 oder VP9 Encoding — Zu langsam ohne GPU
- Komplexe Filter Chains — Subtitles, Overlays, Multi-Input-Compositions
- Berechenbare Verarbeitung im Maßstab — Kosten werden untragbar
- Vollen Codec-Support — Stripped Binaries schränken dich ein
- GPU Acceleration — Auf Serverless nicht verfügbar
Für diese Fälle räumt eine dedizierte Video-Processing-API die Infrastruktur-Probleme komplett ab. Wenn du Managed-Lösungen vergleichst, schau dir an, wie FFHub gegen AWS MediaConvert abschneidet.
FFHub: Cloud FFmpeg ohne Infrastruktur
FFHub liefert eine Cloud-FFmpeg-API, die genau für die Probleme designt ist, die Serverless nicht löst. Du schickst die gleichen FFmpeg-Commands, die du lokal laufen lassen würdest, und FFHub erledigt die Ausführung auf optimierter Infrastruktur.
# Instead of wrestling with Lambda layers and timeouts:
curl -X POST https://api.ffhub.io/v1/command \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"command": "-i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac output.mp4",
"inputs": ["https://storage.example.com/input.mp4"],
"webhook": "https://your-app.com/callback"
}'
Die Vorteile gegenüber Serverless FFmpeg:
- Kein Binary-Management — Vollständiges FFmpeg mit allen Codecs, immer aktuell
- Keine Timeout-Limits — Verarbeite Videos beliebiger Länge
- Optimierte Infrastruktur — Dedizierte Hardware, getunt für Videoverarbeitung
- Gleiche FFmpeg-Syntax — Keine neue API zu lernen
- Pay-per-Use — Keine Kosten für Idle-Infrastruktur
Besonders wertvoll, wenn dein Kernprodukt nicht Videoverarbeitung ist — du solltest keine FFmpeg-Builds und Lambda Layers pflegen, wenn du stattdessen Features bauen könntest.
Entscheidungs-Framework
| Faktor | Serverless nutzen | Dedizierte API nutzen |
|---|---|---|
| Video-Dauer | < 30 Sekunden | Beliebig |
| Aufgabentyp | Thumbnails, Metadaten, Audio Copy | Transcoding, Subtitles, Filter |
| Volumen | < 50/Tag | Beliebig |
| Codec-Bedarf | Nur H.264 | Beliebiger Codec |
| GPU nötig | Nein | Ja (für Speed) |
| Team-Expertise | DevOps-Team verfügbar | Lieber Managed |
Zusammenfassung
FFmpeg auf Serverless laufen zu lassen ist möglich, aber schmerzhaft. Binary-Größe, Timeout-Limits, Memory-Kosten und das Fehlen von GPU machen es zu einer schlechten Wahl für alles jenseits einfacher Aufgaben wie Thumbnails und Audio-Extraktion.
Wenn deine Workload echtes Transcoding bedeutet, denk an die Gesamtkosten — nicht nur die Lambda-Rechnung, sondern die Engineering-Zeit, die in den Bau und die Pflege eigener FFmpeg-Deployments fließt. Für die meisten Teams ist eine dedizierte Video-Processing-API sowohl billiger als auch zuverlässiger als der Versuch, Serverless für einen Use Case zu missbrauchen, für den es nicht gedacht war. Was FFHub als Cloud-FFmpeg-Lösung liefert, oder wie Batch Transcoding per API aussieht — beides findest du in den verlinkten Guides.
Verwandte Artikel
- Was ist FFHub? - Cloud FFmpeg ohne Infrastruktur-Overhead
- Batch Video Transcoding API - Tausende Videos programmatisch verarbeiten via REST API
- FFHub vs. AWS MediaConvert - Ein ehrlicher Vergleich von FFHub und AWS' Managed Transcoding-Service