How to run R code in a sandbox
Run R in an isolated microVM with a code interpreter that returns plots as PNG and data frames as tables, or install R and use Rscript.
On Runtime, R needs no setup at all: the code interpreter installs it the first time you run an R cell, then keeps your variables between cells. On 23 September 2026 that first install took about 90 seconds, once per sandbox, and an image with R skips it (code interpreter). Every sandbox is a Firecracker microVM with its own kernel, and a 2 vCPU, 4 GiB sandbox costs $0.03125 an hour while an analyst reads the last chart (pricing).
R as a notebook
TypeScriptimport { Sandbox } from "withruntime";await using sbx = await Sandbox.create({ timeoutSeconds: 1800 });await sbx.interpreter.run( "df <- data.frame(dose = c(1, 2, 4, 8), response = c(3.1, 5.8, 9.6, 14.2))", { language: "r", timeoutMs: 300_000, // the first R cell installs R },);const fit = await sbx.interpreter.run("coef(lm(response ~ dose, data = df))", { language: "r" });console.log(fit.stdout, fit.results[0]?.data["text/plain"]);const plot = await sbx.interpreter.run("plot(df$dose, df$response, type = 'b')", { language: "r" });const png = plot.results.find((r) => r.data["image/png"]);console.log(png ? "got a chart" : "no chart");const table = await sbx.interpreter.run("df", { language: "r" });console.log(table.results[0]?.data["application/vnd.runtime.table+json"]);Pythonimport base64from withruntime import Sandboxwith Sandbox.create(timeout_seconds=1800) as sbx: sbx.interpreter.run("df <- data.frame(dose = c(1, 2, 4, 8), response = c(3.1, 5.8, 9.6, 14.2))", language="r", timeout_ms=300_000) # the first R cell installs R fit = sbx.interpreter.run("coef(lm(response ~ dose, data = df))", language="r") print(fit["stdout"]) plot = sbx.interpreter.run("plot(df$dose, df$response, type = 'b')", language="r") for result in plot["results"]: if "image/png" in result["data"]: with open("dose.png", "wb") as out: out.write(base64.b64decode(result["data"]["image/png"])) table = sbx.interpreter.run("df", language="r") print(table["results"][0]["data"]["application/vnd.runtime.table+json"])- Plots come back as PNG images, base64 in
image/png, with nopng()ordev.off()in your code. - Data frames come back as tables your app can render.
- Any file a cell hands to
display(.png, .svg, .html, .csv) comes back as a result too. - The first R cell downloads R from Ubuntu's archive, so that sandbox needs
the internet. After that,
sbx.network.set({ internet: false })cuts it off for the code that follows.
Which R to install
For scripts outside the interpreter, or for an image, install R yourself:
| Source | R version on 25 September 2026 | Command |
|---|---|---|
| Ubuntu 24.04 archive (universe) | 4.3.3 | sudo apt-get install -y r-base-core |
| Ubuntu, with headers to build packages | 4.3.3 | sudo apt-get install -y r-base-dev |
| CRAN's Ubuntu repository | 4.6 | Add the noble-cran40 repository, then r-base |
CRAN's own steps for Ubuntu add its signing key and the
$(lsb_release -cs)-cran40 repository, then run
sudo apt install --no-install-recommends r-base
(CRAN). CRAN also points to
r2u, which installs CRAN packages as Ubuntu binaries, so they need no compile.
Run an R script
TypeScriptimport { Sandbox } from "withruntime";const script = `x <- c(12, 15, 11, 19, 22, 17)cat(sprintf("mean %.2f, sd %.2f\\n", mean(x), sd(x)))`;await using sbx = await Sandbox.create({ timeoutSeconds: 900, onLeaseEnd: "stop" });await sbx.exec( "sudo apt-get update -q && sudo apt-get install -y -q --no-install-recommends r-base-core", { check: true, timeoutMs: 600_000, },);await sbx.network.set({ internet: false });await sbx.files.write("/workspace/stats.R", script);const run = await sbx.exec(["Rscript", "stats.R"], { timeoutMs: 60_000 });console.log(run.stdout); // mean 16.00, sd 4.20Pythonfrom withruntime import Sandboxscript = """x <- c(12, 15, 11, 19, 22, 17)cat(sprintf("mean %.2f, sd %.2f\\n", mean(x), sd(x)))"""with Sandbox.create(timeout_seconds=900, on_lease_end="stop") as sbx: sbx.exec("sudo apt-get update -q && sudo apt-get install -y -q --no-install-recommends r-base-core", check=True, timeout_ms=600_000) sbx.network.set(internet=False) sbx.files.write("/workspace/stats.R", script) run = sbx.exec(["Rscript", "stats.R"], timeout_ms=60_000) print(run.stdout) # mean 16.00, sd 4.20An array runs Rscript with no shell in between. A script that loops forever
returns timedOut: true with the output so far.
R and your packages in every sandbox
Build a custom image with R and the packages your analyses use. The interpreter finds R already there and starts its first R cell with no install:
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "r-data", recipe: { apt: ["r-base-dev"], commands: [ `Rscript -e 'install.packages(c("data.table", "jsonlite"), repos = "https://cloud.r-project.org")'`, ], },});await using sbx = await runtime.sandboxes.create({ image: "r-data", network: { internet: false } });const cell = await sbx.interpreter.run("library(data.table); data.table(a = 1:3)[, sum(a)]", { language: "r",});console.log(cell.results[0]?.data["text/plain"]);Pythonfrom withruntime import Runtimeruntime = Runtime()runtime.images.build(name="r-data", recipe={ "apt": ["r-base-dev"], "commands": ["""Rscript -e 'install.packages(c("data.table", "jsonlite"), repos = "https://cloud.r-project.org")'"""],})with runtime.sandboxes.create(image="r-data", network={"internet": False}) as sbx: cell = sbx.interpreter.run("library(data.table); data.table(a = 1:3)[, sum(a)]", language="r") print(cell["results"][0]["data"]["text/plain"])install.packages compiles packages from source, which is why the recipe
takes r-base-dev. The image build runs in its own microVM, and building is
free; a stored image is charged on its size.
R next to Python
One sandbox can hold an R context and a Python context at once, each with its
own variables, so an agent can clean data in pandas and fit a model in R
without leaving the machine. Files in /workspace are shared by both.
Related
- A data analysis agent
- Build a code interpreter for a chatbot
- What is a code interpreter?
- Run untrusted Python code safely
New accounts get 50 free sandbox hours, no card:
Terminalnpx withruntime sandbox run --trial -- bash -c 'sudo apt-get update -q && sudo apt-get install -y -q r-base-core && R --version'Sources
- CRAN, R for Ubuntu (current R 4.6, noble supported, r2u): https://cran.r-project.org/bin/linux/ubuntu/ (read 25 September 2026)
- Ubuntu 24.04 package index (
r-base,r-base-coreandr-base-dev4.3.3-2build2): http://archive.ubuntu.com/ubuntu/dists/noble/universe/binary-amd64/ (read 25 September 2026)
Facts on this page were checked on 25 September 2026.