On Runtime, a notebook run pays for the CPU its cells use, and for memory only while it runs. A nightly report that keeps a 2 vCPU, 4 GiB sandbox for ten minutes costs less than a cent per run. No server sits idle between runs.
Two ways to run a notebook
| Approach | Best for | What you get back |
|---|---|---|
papermill on the .ipynb file |
Scheduled reports with parameters | An executed notebook, one per parameter set |
jupyter nbconvert --execute |
Running a notebook as it is | An executed notebook |
| Runtime's code interpreter | A program or agent sending one cell at a time | Each cell's text, tables and PNG charts |
papermill and nbconvert run the whole file. They write a new notebook that contains every output. A scheduled job or CI pipeline needs this. The interpreter suits code that picks the next cell after it sees the output of the last one, such as an agent.
Build an image with Jupyter
The default image has Python 3.12, pandas 2.1.4, NumPy 1.26.4 and matplotlib 3.6.3. Add the notebook tools and every package your notebooks import:
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "notebooks", recipe: { pip: ["papermill", "nbconvert", "ipykernel", "scikit-learn"] },});Building an image costs nothing. Every run starts with those packages already installed (custom images).
Run a parameterised notebook with papermill
papermill reads the cell tagged parameters. It inserts a new cell tagged
injected-parameters right after it. That cell holds the values you pass with
-p (papermill's documentation, read 26 October 2026).
TypeScriptimport { writeFile } from "node:fs/promises";import { Runtime } from "withruntime";const runtime = new Runtime();await using sbx = await runtime.sandboxes.create({ image: "notebooks", timeoutSeconds: 1800, onLeaseEnd: "stop", labels: { job: "weekly-report" },});await sbx.files.upload("./reports", "/workspace/reports");const run = await sbx.exec( ["papermill", "sales.ipynb", "out/sales-west.ipynb", "-p", "region", "west", "-p", "weeks", "12"], { cwd: "/workspace/reports", timeoutMs: 1_500_000 },);if (run.exitCode !== 0) console.error(run.stderr.slice(-2000)); // the failing cell's tracebackawait writeFile( "sales-west.ipynb", await sbx.files.read("/workspace/reports/out/sales-west.ipynb"),);Pythonfrom withruntime import Runtimeruntime = Runtime()with runtime.sandboxes.create( image="notebooks", timeout_seconds=1800, on_lease_end="stop", labels={"job": "weekly-report"},) as sbx: sbx.files.upload("./reports", "/workspace/reports") run = sbx.exec( ["papermill", "sales.ipynb", "out/sales-west.ipynb", "-p", "region", "west", "-p", "weeks", "12"], cwd="/workspace/reports", timeout_ms=1_500_000, ) if run.exit_code != 0: print(run.stderr[-2000:]) # the failing cell's traceback with open("sales-west.ipynb", "wb") as target: target.write(sbx.files.read("/workspace/reports/out/sales-west.ipynb"))A non-zero exit code means that a cell raised an error. Keep the last part of
stderr for the alert. Keep the output notebook for the person who fixes the
error.
Or run it as it is with nbconvert
Terminaljupyter nbconvert --to notebook --execute --ExecutePreprocessor.timeout=600 analysis.ipynbBy default, nbconvert gives each cell 30 seconds and stops at the first error.
--ExecutePreprocessor.timeout raises the time limit. allow_errors runs the
notebook to the end even after an error (nbconvert's documentation, read 26 October 2026). Put the command in an exec call, as in the papermill example.
Many parameter sets at once
A report for each region, customer or model checkpoint uses the same notebook with different parameters. Give each run its own sandbox, and run them together. A paid account runs 100 sandboxes at the same time. A create request beyond that limit waits for a free slot instead of failing:
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime({ waitForCapacityMs: 600_000 });const regions = ["west", "east", "north", "south"];await Promise.all( regions.map(async (region) => { await using sbx = await runtime.sandboxes.create({ image: "notebooks", labels: { region } }); await sbx.files.upload("./reports", "/workspace/reports"); await sbx.exec(["papermill", "sales.ipynb", `out/${region}.ipynb`, "-p", "region", region], { cwd: "/workspace/reports", timeoutMs: 1_500_000, }); await sbx.files.download(`/workspace/reports/out/${region}.ipynb`, `./out/${region}.ipynb`); }),);Data the notebook reads
- Small inputs are uploaded with the notebook, using
files.upload. - A bucket mounts as a directory. The host's proxy holds the access key, not the sandbox (mount your own bucket).
- A warehouse or API key is stored as a Runtime secret. The notebook reads an environment variable that holds a placeholder. The proxy replaces the placeholder with the real value only on HTTPS requests to the hosts you named (secrets).
What notebook jobs need
| Need | How Runtime covers it |
|---|---|
| The same environment every run | A versioned image; notebooks@4 pins one build |
| A notebook that runs for hours | Commands up to 24 hours; the sandbox has no time limit |
| Charts | Saved in the executed .ipynb; the interpreter returns them as PNG |
| R code | The interpreter runs R cells; R installs on first use, or is baked into the image |
| Someone else's notebook | A microVM of its own; network limited or turned off |
| Knowing a run failed | A sandbox.stopped webhook, or the exit code in your scheduler |
What it costs
A team runs 30 notebooks every night, which is 900 runs a month. Each run keeps a 2 vCPU, 4 GiB sandbox for 10 minutes. Its cells use 6 CPU-minutes (360 CPU-seconds):
- CPU
- 900 × 360 s / 3,600 × $0.025
- $2.25
- Memory
- 900 × 600 s / 3,600 × 4 GiB × $0.0075
- $4.50
- Total
- $6.75
That is 0.75 cents a run, at $0.025 per vCPU-hour of measured CPU and $0.0075 per GiB-hour (pricing). Nothing runs between runs, so nothing is billed. A new account gets 100 free hours of a 1 GB machine in its first 30 days, with no card needed.
Sources
- papermill: execute
and parameterize:
-p, theparameterstag andinjected-parameters, read 26 October 2026. - nbconvert: executing notebooks:
--execute, the 30-second cell timeout andallow_errors, read 26 October 2026.
Related: data analysis agent, what a code interpreter is, code interpreter for chatbots, Python in a sandbox.
Facts on this page were checked on 26 October 2026.