Skip to content
Runtime

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 26 October 2026 that first install took about 15 seconds, once per sandbox. An image with R skips it (code interpreter). Every sandbox is a Firecracker microVM with its own kernel. 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 are returned as PNG images, base64 in image/png. Your code needs no png() or dev.off() call.
  • Data frames are returned as tables that your app can render.
  • Any file that a cell passes to display (.png, .svg, .html, .csv) is returned as a result too.
  • The first R cell downloads R from Ubuntu's archive, so that sandbox needs internet access. After that, sbx.network.set({ internet: false }) turns off the network 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 26 October 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. The next step is sudo apt install --no-install-recommends r-base (CRAN). CRAN also points to r2u. It 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.20
Pythonfrom 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.20

The command is an array, so it runs Rscript with no shell in between. A script that loops forever returns timedOut: true and 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 installed, so its first R cell starts 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. That is why the recipe takes r-base-dev. The image build runs in its own microVM. Building is free. A stored image is billed by its size.

R next to Python

One sandbox can hold an R context and a Python context at the same time. Each has 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.

A new account gets 100 free hours of a 1 GB machine in its first 30 days. No payment card is needed:

Terminalnpx withruntime sandboxes run -- bash -c 'sudo apt-get update -q && sudo apt-get install -y -q r-base-core && R --version'

Sources

Facts on this page were checked on 26 October 2026.

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