DEV Community

Javid Jamae
Javid Jamae

Posted on • Originally published at ffmpeg-micro.com

FFmpeg on AWS Lambda: The Layer-Size and Timeout Problem

Originally published at ffmpeg-micro.com

You're building a serverless video pipeline. You add an FFmpeg static binary as a Lambda layer, wire up an S3 trigger, deploy, and immediately hit a wall. The binary is too big, the storage is too small, and the timeout isn't long enough. I've watched this play out on dozens of projects, and the failure mode is always the same.

The 250 MB Layer Limit

AWS Lambda layers max out at 250 MB unzipped. That's a hard limit, and FFmpeg pushes right up against it.

A typical FFmpeg static build compresses to around 70-80 MB as a zip file. Unzipped, with common codecs included, you're looking at 200 MB or more. That sounds like it fits, but remember: your function code, runtime, and all layers share that 250 MB budget. Once you add the AWS SDK, a couple of Node.js dependencies, and your handler code, you're over.

The usual fix is stripping codecs. You rebuild FFmpeg with only the encoders you need. But the codecs you "don't need" have a way of becoming the codecs you do need. Drop libx265 and someone requests HEVC output. Drop libvpx and a client wants WebM. You end up maintaining a custom FFmpeg build just to stay under a Lambda limit.

A stripped FFmpeg binary with only libx264 still runs about 40-50 MB unzipped. Add libx265 and libvpx, and you're back above 150 MB before your function code enters the picture.

The /tmp Storage Cap

Lambda gives you 512 MB of ephemeral storage in /tmp by default. You can bump this to 10 GB, but you pay for it ($0.0000000309 per GB-second). And you'll need every byte.

FFmpeg doesn't just read an input and write an output. It creates intermediate temp files during encoding. So for a single transcode, you need space for the input file, the output file, and FFmpeg's working files. A 500 MB source video blows through the default 512 MB allocation before the encode even starts. Even with the 10 GB option, a 4K video file can eat that up fast when you factor in temp data.

The 15-Minute Timeout

Lambda functions have a hard ceiling of 15 minutes. You can't extend it, negotiate it, or work around it.

Encoding a 10-minute 1080p video to H.265 takes 20-30 minutes on Lambda's shared vCPUs. That's not a worst case. That's a normal case. Lambda doesn't give you dedicated CPU cores. You're on shared infrastructure, and encoding performance varies between invocations. A job that finishes in 12 minutes on one run might take 18 on the next.

For audio extraction or format remuxing (copying streams without re-encoding), 15 minutes is usually fine. For actual transcoding with compute-intensive codecs, it's not.

The Cold Start Tax

When you outgrow layers and switch to Docker images on Amazon ECR (the standard workaround for binaries larger than 250 MB), you trade the layer-size problem for a cold start problem.

Lambda container images can be up to 10 GB, which solves the binary size issue. But cold starts for container-based Lambda functions run 5-15 seconds, sometimes longer. If your video pipeline is event-driven, processing uploads as they arrive, those cold starts add real latency. A user uploads a short clip expecting a fast turnaround, and the first 10 seconds are just Lambda pulling your container image.

When Lambda + FFmpeg Actually Works

I don't want to pretend Lambda is never the right call. For small, simple jobs, it works fine.

Extracting a thumbnail from a video? Lambda handles that in seconds. Pulling the audio track from an MP4? No problem. Trimming a sub-30-second clip or converting between container formats without re-encoding? All good.

A minimal Lambda handler that extracts a thumbnail using a pre-installed FFmpeg layer:

ffmpeg -i /tmp/input.mp4 -ss 00:00:05 -frames:v 1 /tmp/thumbnail.jpg
Enter fullscreen mode Exit fullscreen mode

If your workload fits this profile (small files, simple operations, no heavy encoding), Lambda plus an FFmpeg layer is a reasonable setup. The trouble starts when the jobs get bigger.

The API Alternative: Call FFmpeg Micro from Your Lambda

Instead of cramming FFmpeg into Lambda, you can keep your Lambda function small and offload the encoding to a dedicated API. Your Lambda becomes a thin orchestration layer. No binary, no layer, no /tmp pressure.

FFmpeg Micro is a cloud API that runs FFmpeg commands over HTTP. You send a POST request with your inputs and options, and get back processed video. No binary to install, no server to manage. Get a free API key at ffmpeg-micro.com.

A TypeScript Lambda handler that starts a transcode job through the FFmpeg Micro API:

import { Handler } from 'aws-lambda';

const FFMPEG_MICRO_KEY = process.env.FFMPEG_MICRO_API_KEY;

export const handler: Handler = async (event) => {
  const { videoUrl, outputFormat = 'mp4' } = event;

  const response = await fetch('https://api.ffmpeg-micro.com/v1/transcodes', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${FFMPEG_MICRO_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      inputs: [{ url: videoUrl }],
      outputFormat,
      preset: { quality: 'high', resolution: '1080p' },
    }),
  });

  const job = await response.json();
  return { jobId: job.id, status: job.status };
};
Enter fullscreen mode Exit fullscreen mode

This Lambda function is a few kilobytes. No layer. No Docker image. No cold start penalty beyond the standard Node.js runtime. The actual encoding happens on FFmpeg Micro's infrastructure, which means no 15-minute timeout concern and no /tmp storage juggling.

You fire the request, get a job ID back, and poll GET /v1/transcodes/{id} for completion. The finished job includes an outputUrl where you can grab the processed file. If you want to avoid polling from Lambda, trigger a second Lambda from a webhook or a Step Functions wait state.

We broke down the full AWS cost picture in FFmpeg on AWS: Cost Breakdown. For a broader comparison, see Self-Hosting FFmpeg vs API.

FAQ

Can FFmpeg run inside AWS Lambda?

Yes, but with significant constraints. AWS Lambda's 250 MB unzipped layer limit, 512 MB default /tmp storage, and 15-minute execution ceiling make it viable only for lightweight FFmpeg tasks like thumbnail extraction, audio stripping, or short clip trimming. Heavy transcoding jobs will hit timeout or storage limits.

How do I add FFmpeg to an AWS Lambda layer?

You package a statically compiled FFmpeg binary into a zip file and upload it as a Lambda layer. The binary must be compiled for Amazon Linux 2 (x86_64 or arm64). Place it in the bin/ directory of your layer zip so it's available at /opt/bin/ffmpeg in your function. Keep total unzipped size under 250 MB across all layers.

What's the maximum video size I can process with FFmpeg on Lambda?

With default settings, you're limited to roughly 150-200 MB input files because /tmp (512 MB) must hold the input, output, and FFmpeg's temp files. You can increase /tmp to 10 GB for additional cost, which raises the practical limit, but the 15-minute timeout becomes the bottleneck for larger files that require re-encoding.

Is there a serverless way to run FFmpeg without Lambda limits?

Calling a managed transcoding API like FFmpeg Micro from your Lambda function removes the binary size, storage, and timeout constraints. Your Lambda stays small and fast while the encoding runs on dedicated infrastructure. AWS also offers Elastic Transcoder and MediaConvert, though both use proprietary job configs rather than standard FFmpeg commands.

How long does FFmpeg take to encode video on Lambda?

On Lambda's shared vCPUs, encoding a 10-minute 1080p video to H.264 typically takes 10-20 minutes. H.265 encoding runs 20-30 minutes for the same input. Performance varies between invocations because CPU resources are shared. Operations that don't re-encode (remuxing, stream copying) finish in seconds.

Top comments (0)