Skip to content
Runtime

How to run FFmpeg in a cloud sandbox

Install Ubuntu's ffmpeg package in a microVM, upload the media, run ffmpeg or ffprobe, and download the output file.

On Runtime, you pay for the CPU an encode uses, and nothing for the minutes around it. A 2 vCPU, 4 GiB sandbox with both CPUs encoding costs $0.08 an hour. So ten minutes of full-load x264 work costs about $0.013. The same sandbox waiting for the next upload costs $0.03125 an hour (pricing). Each job runs in its own Firecracker microVM. This matters for media. A malformed file uploaded by a stranger is parsed on a machine that holds nothing else. Ubuntu 24.04 shipped FFmpeg 6.1.1 on 25 October 2026.

Transcode an upload to web-ready MP4

TypeScriptimport { writeFile } from "node:fs/promises";import { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ diskMiB: 8192, timeoutSeconds: 3600 });await sbx.exec("sudo apt-get update -qq && sudo apt-get install -y -qq ffmpeg", {  check: true,  timeoutMs: 600_000,});await sbx.files.upload("./talk.mov", "/workspace/in.mov");await sbx.exec(  [    "ffmpeg",    "-hide_banner",    "-y",    "-i",    "in.mov",    "-c:v",    "libx264",    "-preset",    "medium",    "-crf",    "23",    "-pix_fmt",    "yuv420p",    "-c:a",    "aac",    "-b:a",    "128k",    "-movflags",    "+faststart",    "out.mp4",  ],  { check: true, timeoutMs: 3_000_000, onStderr: (text) => process.stderr.write(text) },);await sbx.exec(["ffmpeg", "-y", "-ss", "5", "-i", "out.mp4", "-frames:v", "1", "poster.jpg"], {  check: true,});await writeFile("out.mp4", await sbx.files.read("/workspace/out.mp4"));await writeFile("poster.jpg", await sbx.files.read("/workspace/poster.jpg"));
Pythonimport sysfrom withruntime import Sandboxwith Sandbox.create(disk_mib=8192, timeout_seconds=3600) as sbx:    sbx.exec("sudo apt-get update -qq && sudo apt-get install -y -qq ffmpeg",             check=True, timeout_ms=600_000)    sbx.files.upload("talk.mov", "/workspace/in.mov")    sbx.exec(["ffmpeg", "-hide_banner", "-y", "-i", "in.mov",              "-c:v", "libx264", "-preset", "medium", "-crf", "23", "-pix_fmt", "yuv420p",              "-c:a", "aac", "-b:a", "128k", "-movflags", "+faststart", "out.mp4"],             check=True, timeout_ms=3_000_000, on_stderr=sys.stderr.write)    sbx.exec(["ffmpeg", "-y", "-ss", "5", "-i", "out.mp4", "-frames:v", "1", "poster.jpg"],             check=True)    sbx.files.download("/workspace/out.mp4", "out.mp4")    sbx.files.download("/workspace/poster.jpg", "poster.jpg")
  • The command is an array, so it runs without a shell. A file name that a user chose cannot inject shell syntax.
  • FFmpeg writes progress to stderr. onStderr streams it as it happens.
  • Per FFmpeg's format documentation, +faststart moves the MP4's index to the front of the file. A browser can then start playing before the download ends.
  • Uploads and downloads move in parallel 1 MiB chunks. Each chunk is checked by SHA-256. Transfers resume after a dropped connection. The file size is limited only by the sandbox's disk.

Read a file's streams as JSON

ffprobe comes with the package. Its JSON output gives an agent the codec, duration, resolution and bitrate, without text parsing:

TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ image: "ffmpeg" });await sbx.files.upload("./clip.mkv", "/workspace/clip.mkv");const probe = await sbx.exec(  ["ffprobe", "-v", "error", "-of", "json", "-show_format", "-show_streams", "clip.mkv"],  { check: true },);const info = JSON.parse(probe.stdout) as {  format: { duration: string };  streams: { codec_type: string; codec_name: string; width?: number }[];};console.log(  info.format.duration,  info.streams.map((s) => `${s.codec_type}:${s.codec_name}`),);

Encoders in Ubuntu's build

Ubuntu 24.04's libavcodec60 is the library behind its ffmpeg. Per Ubuntu's package archive on 25 October 2026, it depends on these codec libraries:

Library Use it for Name in ffmpeg
libx264-164 H.264 video, for the widest playback -c:v libx264
libx265-199 H.265/HEVC video -c:v libx265
libvpx9 VP8 and VP9 video for WebM -c:v libvpx-vp9
libsvtav1enc1d1 AV1 encoding -c:v libsvtav1
libdav1d7 AV1 decoding (decoder)
libopus0 Opus audio -c:a libopus
libmp3lame0 MP3 audio -c:a libmp3lame

Run ffmpeg -hide_banner -encoders in a sandbox for the full list.

Encodes run on CPUs

Runtime sandboxes have no GPUs. NVENC and other hardware encoders are therefore not available. Every encoder above runs on the CPU. Two ways to go faster:

  • Paid sandboxes can ask for more vcpu than the two allowed without credit. x264 spreads its work across threads. The bill follows the CPU actually used, not the cores reserved.
  • Many files at the same time: give each its own sandbox. A paid account runs 100 at once, and an account without credit runs four.
TypeScriptimport { Sandbox } from "withruntime";const files = ["a.mov", "b.mov", "c.mov"];await Promise.all(  files.map(async (name) => {    await using sbx = await Sandbox.create({ image: "ffmpeg", diskMiB: 8192 });    await sbx.files.upload(`./${name}`, `/workspace/${name}`);    await sbx.exec(["ffmpeg", "-y", "-i", name, "-c:v", "libx264", "-crf", "23", "out.mp4"], {      check: true,      timeoutMs: 3_000_000,    });    await sbx.files.download("/workspace/out.mp4", `./${name}.mp4`);  }),);

Start every sandbox with FFmpeg installed

The samples above that say image: "ffmpeg" use this custom image:

TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "ffmpeg", recipe: { apt: ["ffmpeg"] } });
Pythonfrom withruntime import RuntimeRuntime().images.build(name="ffmpeg", recipe={"apt": ["ffmpeg"]})

Building is free. Without credit, a build counts toward the free usage. An account without credit stores three images free.

Disk and time

Limit What to set
Disk Input, output and FFmpeg itself share it. The default 4 GiB had about 2.5 GiB free on 24 September 2026. 10 GiB is allowed without credit
Disk speed Up to about 1 GB/s when the server is quiet. At least about 40 MB/s when it is busy
One command 60 seconds by default, up to 24 hours with timeoutMs
Sandbox lifetime timeoutSeconds, up to 24 hours. extend changes it, and keepAlive holds the sandbox while your process runs

For media that comes from users, turn off the sandbox's internet after the install. A crafted file then cannot call out (turn off sandbox internet). To generate images or thumbnails in other formats, see ImageMagick in a sandbox. Document and PDF pipelines are covered in document conversion. Batch jobs across many sandboxes are covered in AI data pipelines.

Sources

Facts on this page were checked on 25 October 2026.

Related.

100 free hoursin your first 30 days.

of a 1 GB machine

  • No credit card
  • Four sandboxes at once, 2 vCPU and 4 GiB each
  • Then prepaid credit from $10, no plan fee
Start free, no card
Start free, no card