On Runtime, Elixir installs with one command, and each run gets a whole
virtual machine, not just a BEAM process. Each sandbox is a Firecracker
microVM that runs Ubuntu 24.04.5 with passwordless sudo. This means apt-get install elixir or the script from elixir-lang.org works unchanged. A 2 vCPU, 4 GiB
sandbox costs $0.03125 an hour while it waits and $0.08 an hour with both cores
busy. Runtime bills the CPU the code uses (pricing).
Which Elixir to install
Elixir is not in the default image. There are two installation routes. Both were read on 26 October 2026:
| Route | Elixir | Erlang/OTP | Command |
|---|---|---|---|
| Ubuntu 24.04 (noble) packages | 1.14.0 | 25.3.2.8 | sudo apt-get install -y elixir |
elixir-lang.org install.sh |
1.20.4 | 29.1.2 | sh install.sh elixir@1.20.4 otp@29.1.2 |
The apt route is one line. It also installs the Erlang runtime that Elixir needs
(erlang-base and related packages). The install script fetches the current
release and installs it under $HOME/.elixir-install/installs. In a sandbox,
that path is /workspace/.elixir-install/installs
(install Elixir).
Run a script
.exs files run directly with elixir. They need no project and no compile
step.
TypeScriptimport { Sandbox } from "withruntime";const script = `words = ~w(the quick brown fox jumps over the lazy dog)words|> Enum.frequencies_by(&String.length/1)|> Enum.sort()|> IO.inspect()`;await using sbx = await Sandbox.create({ timeoutSeconds: 600, onLeaseEnd: "stop" });await sbx.exec("sudo apt-get update -q && sudo apt-get install -y -q elixir", { check: true, timeoutMs: 600_000,});await sbx.network.set({ internet: false });await sbx.files.write("/workspace/count.exs", script);const run = await sbx.exec(["elixir", "count.exs"], { timeoutMs: 30_000 });console.log(run.exitCode, run.timedOut, run.stdout);Pythonfrom withruntime import Sandboxscript = """words = ~w(the quick brown fox jumps over the lazy dog)words|> Enum.frequencies_by(&String.length/1)|> Enum.sort()|> IO.inspect()"""with Sandbox.create(timeout_seconds=600, on_lease_end="stop") as sbx: sbx.exec("sudo apt-get update -q && sudo apt-get install -y -q elixir", check=True, timeout_ms=600_000) sbx.network.set(internet=False) sbx.files.write("/workspace/count.exs", script) run = sbx.exec(["elixir", "count.exs"], timeout_ms=30_000) print(run.exit_code, run.timed_out, run.stdout)A script that raises an error exits with a non-zero code. The error and stack trace go to stderr. They give a model what it needs to correct its code.
Why a sandbox and not a BEAM process
Elixir code can call System.cmd/2, :os.cmd/1, File.rm_rf!/1 or open a
socket. Running untrusted code inside your own node gives it all of your node's
rights. In a sandbox, the whole Erlang VM runs inside a microVM with its own
kernel. The network, CPU, memory and cost limits are enforced on the host. Root
in the sandbox cannot change them (security).
Run a Mix project's tests
Mix needs Hex to fetch dependencies. Fetch them while the network is on. Then turn off the network before the tests run:
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ image: "elixir", timeoutSeconds: 1800, onLeaseEnd: "stop",});await sbx.files.upload("./my_app", "/workspace/my_app");const opts = { cwd: "/workspace/my_app", env: { MIX_ENV: "test" }, timeoutMs: 900_000 };await sbx.exec("mix local.hex --force && mix deps.get && mix compile", { ...opts, check: true });await sbx.network.set({ internet: false });const tests = await sbx.exec(["mix", "test"], { ...opts, onStdout: (t) => process.stdout.write(t),});process.exitCode = tests.exitCode ?? 1;This uses the elixir image built below. Output streams back while the tests
run.
Use the newest Elixir
Elixir's install script installs OTP and Elixir side by side. Add both bin
folders to PATH for the command:
Pythonfrom withruntime import Sandboxhome = "/workspace/.elixir-install/installs"path = f"{home}/otp/29.1.2/bin:{home}/elixir/1.20.4-otp-29/bin:/usr/local/bin:/usr/bin:/bin"with Sandbox.create(timeout_seconds=900, on_lease_end="stop") as sbx: sbx.exec("curl -fsSO https://elixir-lang.org/install.sh && sh install.sh elixir@1.20.4 otp@29.1.2", check=True, timeout_ms=600_000) print(sbx.exec(["elixir", "--version"], env={"PATH": path}).stdout)Start every sandbox with Elixir
A recipe installs the Ubuntu packages once. erlang-dev adds the headers that
dependencies with native code compile against. Building is free. A stored image
is billed by its size (custom images).
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "elixir", recipe: { apt: ["elixir", "erlang-dev"] } });await using sbx = await runtime.sandboxes.create({ image: "elixir" });console.log((await sbx.exec(["elixir", "--version"])).stdout);Terminalruntime images build --apt elixir,erlang-dev --name elixirTo keep a node running between requests, start it with sbx.spawn. The call
returns immediately, and the process keeps running after your connection ends.
When the sandbox is idle, pause it. A
pause keeps memory and processes, and compute billing stops.
A new account gets 100 free hours of a 1 GB machine in its first 30 days. No payment card is needed:
Terminalnpx withruntime loginSee also running untrusted LLM code, grading student code and per-user dev environments.
Sources
Checked 26 October 2026.
- Install Elixir:
install.sh, Elixir 1.20.4 and OTP 28.4 - Ubuntu 24.04 (noble) packages: elixir, erlang-nox, erlang-dev
Facts on this page were checked on 26 October 2026.