On Runtime a 45-minute training run on 4 vCPU and 8 GiB costs 12 cents with all four cores busy, at the rates in effect on 26 October 2026. Billing stops the moment the run ends. Runtime runs on CPUs only, with no GPU sandboxes. It fits classical models such as gradient-boosted trees and linear models, and small neural networks, but not large deep learning models.
The short answer
Build the image once, upload the data, train, and download the model:
TypeScriptimport { readFile, writeFile } from "node:fs/promises";import { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "train", recipe: { pip: ["scikit-learn", "joblib"] } }); // onceawait using sbx = await runtime.sandboxes.create({ image: "train", vcpu: 4, memoryMiB: 8192, network: { internet: false }, // training needs nothing from outside});await sbx.files.write("/workspace/data/train.csv", await readFile("train.csv"));await sbx.files.write( "/workspace/train.py", [ "import joblib, pandas as pd", "from sklearn.ensemble import HistGradientBoostingClassifier", "from sklearn.model_selection import train_test_split", "df = pd.read_csv('data/train.csv')", "X, y = df.drop(columns=['label']), df['label']", "X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=0)", "model = HistGradientBoostingClassifier(max_iter=300).fit(X_tr, y_tr)", "print('accuracy', model.score(X_te, y_te))", "joblib.dump(model, 'model.joblib')", ].join("\n"),);const run = await sbx.exec("python3 train.py", { check: true, timeoutMs: 3_600_000 });console.log(run.stdout);await writeFile("model.joblib", await sbx.files.read("/workspace/model.joblib"));Pythonfrom withruntime import RuntimeTRAIN = """import joblib, pandas as pdfrom sklearn.ensemble import HistGradientBoostingClassifierfrom sklearn.model_selection import train_test_splitdf = pd.read_csv('data/train.csv')X, y = df.drop(columns=['label']), df['label']X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=0)model = HistGradientBoostingClassifier(max_iter=300).fit(X_tr, y_tr)print('accuracy', model.score(X_te, y_te))joblib.dump(model, 'model.joblib')"""runtime = Runtime()runtime.images.build(name="train", recipe={"pip": ["scikit-learn", "joblib"]}) # oncewith runtime.sandboxes.create(image="train", vcpu=4, memory_mib=8192, network={"internet": False}) as sbx: with open("train.csv", "rb") as file: sbx.files.write("/workspace/data/train.csv", file.read()) sbx.files.write("/workspace/train.py", TRAIN) print(sbx.exec("python3 train.py", check=True, timeout_ms=3_600_000).stdout) with open("model.joblib", "wb") as file: file.write(sbx.files.read("/workspace/model.joblib"))pandas and NumPy are already in the default image, so the recipe adds only the
packages that training needs. An exec can run for up to 24 hours. The sandbox
has no time limit, so a long run needs no extra setup.
Small neural networks with PyTorch on CPU
PyTorch publishes CPU-only builds on its own package index. Use them on a
machine with no GPU. A recipe's commands run that install while the image
builds:
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({ name: "torch-cpu", recipe: { commands: ["pip install torch --index-url https://download.pytorch.org/whl/cpu"], pip: ["numpy", "pandas"], },});await using sbx = await runtime.sandboxes.create({ image: "torch-cpu", vcpu: 4, memoryMiB: 8192 });const check = await sbx.exec( "python3 -c 'import torch; print(torch.__version__, torch.get_num_threads())'",);console.log(check.stdout);The check prints the number of threads PyTorch uses. Compare it with the
sandbox's vcpu to confirm that training uses every core. Size the model to the
machine. A multilayer perceptron on tabular data or a small convolutional
network is a CPU workload. This page does not cover a model that needs a GPU to
train in a reasonable time.
Search hyperparameters in parallel
Each trial runs in its own sandbox, so a search runs as wide as the account allows: up to 200 vCPUs at the same time on a paid account, initially. Prepare one sandbox with the data on disk, then fork it. Each copy starts with the files, installed packages and memory of the original, so no copy downloads the data again.
TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await using base = await runtime.sandboxes.create({ image: "train", vcpu: 4, memoryMiB: 8192 });// train.py, which takes --learning-rate, and its data/ folder:await base.files.upload("./trainer", "/workspace/trainer");const rates = ["0.03", "0.1", "0.3"];const copies = await base.fork({ count: rates.length });const scores = await Promise.all( copies.map(async (copy, i) => { const run = await copy.exec(["python3", "train.py", "--learning-rate", rates[i]!], { cwd: "/workspace/trainer", timeoutMs: 3_600_000, }); await copy.stop(); return [rates[i], run.stdout.trim()]; }),);console.log(scores);Copies have the source's size and are billed as if each were created at that size. The snapshot that a fork takes for itself is deleted and is never charged (snapshots and forks).
Keep checkpoints and datasets
| What | Where to put it | Cost |
|---|---|---|
| A dataset used by many runs | A read-only volume copy, or your bucket mounted as /data |
Volume: 153 microdollars per GiB-hour |
| Checkpoints during a run | A read-write volume; run sync after each save |
Charged on the volume's full size |
| The finished model | files.read to your own storage |
No Runtime charge after the sandbox stops |
| The whole trained machine | A snapshot, kept for as long as the account has credit | $0.08 per GB per 30-day month |
What CPU training needs
| Need | How Runtime covers it |
|---|---|
| ML libraries | pip packages in a recipe image; NumPy and pandas in the default image |
| All cores working | Shared CPU bursts up to vcpu; cpu: "reserved" guarantees every vCPU |
| Training data kept private | network: { internet: false }, enforced on the host |
| Parallel trials | Forks with memory and files; 100 sandboxes at the same time on a paid account |
| Runs longer than an hour | exec up to 24 hours; no time limit |
| Watching the run | sbx.metrics() for measured CPU and memory |
What it costs
One run of 45 minutes on 4 vCPU and 8 GiB, with all four cores busy throughout:
- CPU
- 0.75 h × 4 vCPU × $0.025
- $0.075
- Memory
- 0.75 h × 8 GiB × $0.0075
- $0.045
- Total
- $0.12
Fifty such runs a month cost $6.00. A run that waits on data loading uses less measured CPU and costs less, with a floor of a twentieth of a vCPU. Runtime charges $0.025 per vCPU-hour of measured CPU and $0.0075 per GiB-hour of memory (pricing).
Start
Terminalnpx withruntime sandboxes run -- python3 -c 'import numpy, pandas; print(numpy.__version__, pandas.__version__)'Approve the connection in your browser the first time you run it. Without credit, a sandbox can use up to 2 vCPU and 4 GiB. Add credit to use 4 vCPU or more.
Related: scientific computing, data analysis agent, RL environments, Python in a sandbox.
Sources
- PyTorch: previous versions:
CPU-only wheels installed with
--index-url https://download.pytorch.org/whl/cpu, read 26 October 2026.
Facts on this page were checked on 26 October 2026.