# How to install Python packages with uv in a sandbox uv is preinstalled: run `uv venv`, then `uv pip install `, or `uv sync` in a project that has a `uv.lock`. **On Runtime uv is part of the default image, so there is nothing to install before you install.** Every sandbox has uv 0.12.17 (`uv` and `uvx`) beside Python 3.12 and pip ([what is installed](/docs/sandbox-environment#what-is-installed)), inside a Firecracker microVM of its own where a package's install script runs away from your machine. uv's own documentation calls it "10-100x faster than pip" and a drop-in replacement for common pip commands. A new sandbox ran its first Python command 351 ms after the create request at the median on 24 September 2026 ([speed](/docs/speed)). ## Install into a virtual environment ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create(); const slow = { check: true, timeoutMs: 300_000 } as const; await sbx.exec("uv venv /workspace/.venv", slow); await sbx.exec("uv pip install polars httpx", { ...slow, cwd: "/workspace" }); const run = await sbx.exec([".venv/bin/python", "-c", "import polars; print(polars.__version__)"]); console.log(run.stdout); ``` ```python check from withruntime import Sandbox with Sandbox.create() as sbx: sbx.exec("uv venv /workspace/.venv", check=True, timeout_ms=300_000) sbx.exec("uv pip install polars httpx", cwd="/workspace", check=True, timeout_ms=300_000) run = sbx.exec([".venv/bin/python", "-c", "import polars; print(polars.__version__)"]) print(run.stdout) ``` ```bash no-run runtime sandbox exec "${id}" -- uv venv /workspace/.venv runtime sandbox exec "${id}" --cwd /workspace --timeout 300 -- uv pip install polars httpx ``` `uv pip install` finds `.venv` in the working directory, which is why the second command runs in `/workspace`. It looks for a virtual environment rather than writing into the system Python. ## Install a project from its lockfile A project with `pyproject.toml` and `uv.lock` installs exactly the versions it locked. Upload it, sync, and run: ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create({ timeoutSeconds: 1800 }); await sbx.files.upload("./service", "/workspace/service"); const inProject = { cwd: "/workspace/service", check: true, timeoutMs: 600_000 } as const; await sbx.exec("uv sync --frozen", inProject); const tests = await sbx.exec("uv run pytest -q", { ...inProject, check: false }); console.log(tests.exitCode, tests.stdout); ``` ```python check from withruntime import Sandbox with Sandbox.create(timeout_seconds=1800) as sbx: sbx.files.upload("./service", "/workspace/service") sbx.exec("uv sync --frozen", cwd="/workspace/service", check=True, timeout_ms=600_000) tests = sbx.exec("uv run pytest -q", cwd="/workspace/service", timeout_ms=600_000) print(tests.exit_code, tests.stdout) ``` `--frozen` uses the lockfile as it is, without checking whether it is up to date, so a sandbox runs what your laptop and CI ran. For a one-off tool, `uvx ruff check .` runs it in a throwaway environment, and `uv run --with requests script.py` adds a package for one run. ## Start every sandbox with the environment ready Build the environment into a [custom image](/docs/images). Recipe commands run as root, so put the environment outside `/workspace` and call its Python by path: ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); await runtime.images.build({ name: "uv-data", recipe: { commands: ["uv venv /opt/venv", "uv pip install --python /opt/venv/bin/python polars duckdb"], }, }); await using sbx = await runtime.sandboxes.create({ image: "uv-data" }); await sbx.exec(["/opt/venv/bin/python", "-c", "import duckdb, polars"], { check: true }); ``` Building is free. A stored image costs $0.08 per decimal GB per 30-day month, and the free trial stores your first three free ([pricing](/docs/pricing#snapshots-images-and-volumes)). A recipe's `pip` list is the shorter path when plain pip is enough. ## uv or pip? | Task | uv | pip in the sandbox | | ------------------------------ | --------------------------------------- | ---------------------------------------------------------- | | Quick install for one job | `uv venv` then `uv pip install ...` | `pip install ...`, no environment needed | | Exact versions from a lockfile | `uv sync --frozen` | `pip install -r requirements.txt` (pinned) | | Run a CLI tool once | `uvx ` | `pip install` then run it | | Another Python version | `uv run --python 3.13 ...` downloads it | Not with pip | | Where packages go | The virtual environment you made | `/workspace/.local` as the user, `/usr/local` under `sudo` | Plain `pip install` works without a virtual environment here: the image's `/etc/pip.conf` sets `break-system-packages`, so Ubuntu's PEP 668 guard does not stop it ([who you are](/docs/sandbox-environment#who-you-are)). ## Mistakes and how Runtime handles them - **`uv pip install` with no environment.** uv expects a virtual environment and does not change the system Python unless told to with `--system`. Make one with `uv venv`, or use pip for a system-wide install. - **A command that times out.** A large install can pass the 60-second default for a command. Give it `timeoutMs`; a timeout returns the output so far. - **An allow list without the package index.** With narrowed network rules, allow `pypi.org` and `*.pythonhosted.org`, or install before turning the internet off ([turn off sandbox internet](/how-to/turn-off-sandbox-internet)). - **Keeping the key to a private index.** Store it as a [secret the sandbox never sees](/docs/security#secrets-sandboxes-never-see): the proxy adds it on HTTPS requests to the index's host only. - **Disk.** Wheels for large libraries fill a small disk. The default 4 GiB sandbox had about 2.5 GiB free on 24 September 2026; ask for more with `diskMiB`. ## Related - [Run untrusted Python code safely](/languages/python). - [Install apt packages](/how-to/install-apt-packages) for system libraries. - [A data analysis agent](/use-cases/data-analysis-agent) that installs what its code imports. ## Start ```bash no-run npx withruntime sandbox run --trial -- uvx pycowsay hello from uv ``` New accounts get 50 free sandbox hours, no card. The first run prints a link to approve in your browser. ## Sources - uv documentation: https://docs.astral.sh/uv/, https://docs.astral.sh/uv/pip/, https://docs.astral.sh/uv/pip/environments/, https://docs.astral.sh/uv/concepts/projects/sync/, https://docs.astral.sh/uv/guides/scripts/ and https://docs.astral.sh/uv/guides/tools/, read 25 September 2026. Facts on this page were checked on 25 September 2026.