Can You Run FFmpeg on Cloudflare Workers?
Workers cannot run the native FFmpeg binary. Here are the real options — WebAssembly, Media Transformations, Containers or an FFmpeg API — and their limits.
No, you cannot run the native FFmpeg binary on Cloudflare Workers. Workers run JavaScript and WebAssembly in isolates with 128 MB of memory, and there is no operating system process to start a binary in. You have four real options: a WebAssembly build of FFmpeg for very small jobs, Cloudflare Media Transformations for simple short clips, Cloudflare Containers for the native binary, or an FFmpeg API that you call from the Worker.
This guide gives the limits of each, with the numbers from Cloudflare’s docs. For a comparison with Lambda, Vercel and VMs, see how to run FFmpeg in the cloud.
The Workers limits that matter for video
| Limit | Workers Free | Workers Paid |
|---|---|---|
| Memory per isolate | 128 MB | 128 MB |
| CPU time per HTTP request | 10 ms | 30 s default, up to 5 minutes |
| Worker size (uncompressed) | 64 MiB | 64 MiB |
| Request body | 100 MB on the Free and Pro Cloudflare plans; more on Business and Enterprise | Same |
Source: Workers limits, checked on 16 October 2026.
The memory limit is per isolate and covers the JavaScript heap and WebAssembly allocations together. Waiting on fetch() does not count toward CPU time, but encoding video does.
Option 1: FFmpeg compiled to WebAssembly
WebAssembly builds of FFmpeg (such as ffmpeg.wasm) run without a native binary. In a Worker they have two hard limits:
- Memory. The input file, the output file and the codec buffers must fit in 128 MB with your own code. One decoded 1080p frame takes about 3 MB (1920 × 1080 pixels in YUV 4:2:0), so codec buffers grow quickly.
- CPU time. Software encoding in WebAssembly is slow, and every millisecond of it counts toward the CPU limit.
Use it for: reading metadata, cutting tiny clips, or work on short audio. Not for: transcoding user uploads.
Option 2: Cloudflare Media Transformations
Media Transformations let you transform a video by URL (/cdn-cgi/media/<options>/<source>) or with a binding from a Worker. They can resize and crop, cut a clip, extract a still frame or a sprite sheet, and extract audio.
| Limit | Value |
|---|---|
| Input size | Less than 100 MB |
| Input duration | 10 minutes |
| Output video duration | 1 to 60 seconds |
| Input format | MP4 with H.264 video and AAC or MP3 audio (others untested) |
| Output size | 10 to 2,000 pixels for width and height |
Pros: nothing to run, cached at the edge, good for previews and thumbnails of short videos already in R2. Cons: a fixed set of options, not FFmpeg commands. No filter graphs, no codec choice, no long outputs, no files over 100 MB.
Option 3: Cloudflare Containers
Cloudflare Containers run a Linux image you provide, started and controlled from a Worker. Put FFmpeg in the image and the Worker can send it jobs.
Pros: the native binary with any flags, close to your Workers and R2. Cons: you build the job system — queueing, timeouts, retries, scaling and cleanup — and operate the image.
Option 4: Call an FFmpeg API from the Worker
Keep the Worker as the place where your app logic runs, and send the FFmpeg work out with fetch. With Xora, the request carries the same FFmpeg arguments you would run locally:
export default { async fetch(request: Request, env: { XORA_API_KEY: string }): Promise<Response> { const { videoUrl } = (await request.json()) as { videoUrl: string }
const res = await fetch('https://api.xora.sh/v1/jobs', { method: 'POST', headers: { Authorization: `Bearer ${env.XORA_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ mode: 'ffmpeg', input_files: { in_1: videoUrl }, output_files: { out_1: 'clip_720p.mp4' }, ffmpeg: { args: ['-i', '{{in_1}}', '-vf', 'scale=-2:720', '-c:v', 'libx264', '-crf', '23', '-c:a', 'aac', '{{out_1}}'], }, webhookUrl: 'https://your-worker.example.com/webhooks/xora', }), })
return new Response(await res.text(), { status: res.status, headers: { 'Content-Type': 'application/json' } }) },}The Worker spends almost no CPU time: it waits on one fetch. Xora calls the webhook when the job ends. The input can be any URL Xora can read, including a presigned R2 URL.
This fits a Cloudflare stack well in one more way: on paid plans, Xora can write outputs straight into your own R2 bucket, so the finished file is already in the bucket your Worker serves from. Credits are billed for machine time and output size, and failed and rejected jobs cost nothing. See pricing.
Which option to pick
| You need | Pick |
|---|---|
| Metadata or a tiny clip, no extra service | WebAssembly, if it fits in 128 MB |
| Thumbnails or short previews of MP4s under 100 MB | Media Transformations |
| Native FFmpeg and you want to run the infrastructure | Containers |
| Native FFmpeg with any flags, large files (up to your plan’s limit), nothing to operate | An FFmpeg API |
Next steps
- How to run FFmpeg in the cloud: all four approaches compared.
- FFmpeg cheat sheet: the common commands as API calls.
- Bring your own R2 bucket: outputs written to your storage.
Frequently asked questions
Can Cloudflare Workers run FFmpeg?
Not the native FFmpeg binary. Workers run JavaScript and WebAssembly in V8 isolates with 128 MB of memory, and there is no process to start a binary in. A WebAssembly build of FFmpeg can do small jobs if everything fits in that memory. For real transcodes, use Cloudflare Containers, Media Transformations for simple short clips, or call an FFmpeg API from the Worker.
Does ffmpeg.wasm work in a Worker?
Only for small inputs. The 128 MB memory limit covers the JavaScript heap and all WebAssembly allocations together, so the input, the output and the codec state must all fit. CPU time per request is also limited: 10 ms on the Free plan, and 30 seconds by default (up to 5 minutes) on the Paid plan.
What are the limits of Cloudflare Media Transformations?
The input must be less than 100 MB and at most 10 minutes long, and the output video is at most 60 seconds. The input should be an MP4 with H.264 video and AAC or MP3 audio. It supports a fixed set of options (resize, crop, clip, still frames, sprite sheets and audio), not custom FFmpeg commands.
How do I process video from a Worker without running FFmpeg in it?
Send the job to an FFmpeg API with fetch. The Worker sends a small JSON request with the FFmpeg arguments and the input URL, and the API calls a webhook when the job ends. With Xora, outputs can go straight into your own Cloudflare R2 bucket on paid plans.