# How to install apt packages in a sandbox Run `sudo apt-get update && sudo apt-get install -y ` in the sandbox; `sudo` needs no password, because you are root inside it. **On Runtime you are root in a Linux machine of your own, so apt works as on any Ubuntu 24.04 server.** Every sandbox is a Firecracker microVM with its own kernel, and root inside it still cannot change its network rules, CPU, memory or cost, which the host enforces from outside. Install into one sandbox when you need a package once, or build it into a custom image and every sandbox starts with it: building is free, and a stored image costs $0.08 per decimal GB per 30-day month ([pricing](/docs/pricing#snapshots-images-and-volumes)). ## Install into a running sandbox ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create({ diskMiB: 8192 }); const apt = { check: true, timeoutMs: 600_000, env: { DEBIAN_FRONTEND: "noninteractive" } }; await sbx.exec("sudo -E apt-get update -q", apt); await sbx.exec("sudo -E apt-get install -y -q ffmpeg imagemagick", apt); console.log((await sbx.exec("ffmpeg -version | head -1")).stdout); ``` ```python check from withruntime import Sandbox with Sandbox.create(disk_mib=8192) as sbx: env = {"DEBIAN_FRONTEND": "noninteractive"} sbx.exec("sudo -E apt-get update -q", env=env, check=True, timeout_ms=600_000) sbx.exec("sudo -E apt-get install -y -q ffmpeg imagemagick", env=env, check=True, timeout_ms=600_000) print(sbx.exec("ffmpeg -version | head -1").stdout) ``` ```bash no-run runtime sandbox exec "${id}" -- sudo apt-get update -q runtime sandbox exec "${id}" --timeout 600 -- sudo apt-get install -y ffmpeg ``` - `-y` answers apt's "Do you want to continue?" A command in a sandbox has no one to answer it. - `DEBIAN_FRONTEND=noninteractive`, kept by `sudo -E`, stops packages such as `tzdata` from asking questions during setup. - An install takes longer than a command's 60-second default, so give it `timeoutMs`. A timeout is a result with the output so far, not an exception. ## Install once, in an image A recipe's `apt` list installs packages at build time. Every sandbox made from the image has them the moment it starts: ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); await runtime.images.build( { name: "media", recipe: { apt: ["ffmpeg", "imagemagick", "poppler-utils"] } }, { onLog: (line) => console.log(line.text) }, ); await using sbx = await runtime.sandboxes.create({ image: "media" }); await sbx.exec("pdftotext -v", { check: true }); ``` ```python check from withruntime import Runtime runtime = Runtime() runtime.images.build(name="media", recipe={"apt": ["ffmpeg", "imagemagick", "poppler-utils"]}, on_log=lambda line: print(line["text"])) with runtime.sandboxes.create(image="media") as sbx: sbx.exec("pdftotext -v", check=True) ``` ```bash no-run runtime image build --apt ffmpeg --apt imagemagick --name media runtime sandbox create --image media ``` A recipe also takes `pip`, `npm`, `commands`, `files`, `env` and `workdir`, and `base` to start from any image instead of Runtime's. Each build of a name is its next version, tagged `latest`, so `image: "media"` always picks the newest ([custom images](/docs/images#build-from-an-image-or-a-recipe)). ## Which way to choose | Way | When it fits | Cost | | ----------------------------------- | ---------------------------------------------- | ------------------------------------------ | | `sudo apt-get install` in a sandbox | One job, or packages that differ per run | The sandbox's own time while it installs | | Recipe `apt` in a custom image | The same packages in every sandbox | Free to build; $0.08 per GB-month to store | | A Dockerfile with `RUN apt-get ...` | You already have one | The same as any image | | A paused sandbox | One machine you come back to, packages and all | Paused storage while it waits | The free trial stores your first three images free, even after you add credit. ## What is already there The default image is Ubuntu 24.04.5 LTS for amd64. Before reaching for apt, check the list: Python 3.12 with pip and uv, Node.js 24 and Bun, `gcc`, `g++` and `make`, `git`, `curl`, `wget`, `ssh`, `zip`, `unzip`, `xz`, `rg`, `fd`, `jq` and `sqlite3` are all installed ([what is installed](/docs/sandbox-environment#what-is-installed)). Java, Go and Rust install from Ubuntu's packages with `sudo apt-get install`, or from the language's own installer such as `rustup`. Docker has its own command, `sudo enable-docker` ([how to](/how-to/run-docker-in-a-sandbox)). ## Mistakes and how Runtime handles them - **Running out of disk.** `diskMiB` includes the system image. The default 4 GiB sandbox had about 2.5 GiB free on 24 September 2026, so ask for more before a large install, such as `diskMiB: 8192`. - **Leaving out `sudo`.** apt needs root. `sudo` works without a password and keeps the proxy settings the sandbox needs to reach the internet. - **Installing, then locking the network first.** An allow list that leaves out the package archive makes `apt-get update` fail. Install first, then narrow or turn off the internet ([turn off sandbox internet](/how-to/turn-off-sandbox-internet)). - **Expecting packages in the next sandbox.** A new sandbox starts from its image. Put the packages in the image, or pause this sandbox and wake it later, files and memory kept ([pause and resume](/how-to/pause-and-resume-a-sandbox)). ## Start ```bash no-run npx withruntime sandbox run --trial --timeout 600 -- bash -c 'sudo apt-get update -q && sudo apt-get install -y cowsay && /usr/games/cowsay hi' ``` New accounts get 50 free sandbox hours, no card. The first run prints a link to approve in your browser. For Python packages, see [install Python packages with uv](/how-to/install-python-packages-with-uv). Facts on this page were checked on 25 September 2026.