Running Code
Running code is the core operation in Runra Sandbox. This guide covers everything from basic command execution to advanced patterns like streaming output and error recovery.
Basic execution
Section titled “Basic execution”The exec() method runs a shell command inside the sandbox:
const result = await sandbox.exec("echo 'Hello, world!'");console.log(result.stdout); // "Hello, world!\n"console.log(result.stderr); // ""console.log(result.exitCode); // 0The ExecutionResult type
Section titled “The ExecutionResult type”Every exec() call returns an ExecutionResult:
interface ExecutionResult { stdout: string; // Standard output stderr: string; // Standard error exitCode: number; // Process exit code (0 = success) durationMs: number; // Execution time in milliseconds signal: string | null; // Signal that killed the process, if any}Exit codes
Section titled “Exit codes”Non-zero exit codes indicate errors. Always check exitCode:
const result = await sandbox.exec("npm test");
if (result.exitCode !== 0) { console.error(`Tests failed with exit code ${result.exitCode}`); console.error(result.stderr); // Handle failure — maybe notify, retry, or abort}Common exit codes
Section titled “Common exit codes”| Code | Meaning | Response |
|---|---|---|
0 | Success | Continue |
1 | General error | Check stderr for details |
2 | Misuse of shell builtins | Check command syntax |
126 | Command invoked cannot execute | Check permissions |
127 | Command not found | Install missing tool |
130 | Script terminated by Ctrl+C | Handle interruption |
137 | Killed (SIGKILL) | Usually OOM — increase memory |
143 | Terminated (SIGTERM) | Graceful shutdown signal |
Streaming output
Section titled “Streaming output”For long-running commands, stream stdout and stderr in real time:
const stream = await sandbox.exec("npm run build", { onStdout: (line: string) => { console.log(`[stdout] ${line}`); // Parse build progress, update UI, etc. }, onStderr: (line: string) => { console.warn(`[stderr] ${line}`); // Track warnings },});
// Stream also returns the final ExecutionResultconsole.log(`Build completed with exit code ${stream.exitCode}`);Handling large output
Section titled “Handling large output”By default, stdout and stderr are fully buffered. For commands that produce a lot of output, use streaming to avoid memory issues:
// For a command that generates GBs of logsconst lines: string[] = [];await sandbox.exec("find / -type f", { onStdout: (line) => { // Process incrementally instead of buffering everything if (line.includes("node_modules")) return; lines.push(line); if (lines.length > 10000) { lines.splice(0, 5000); // Keep a sliding window } },});Environment variables
Section titled “Environment variables”Pass environment variables to sandbox commands:
// Set per-command environmentconst result = await sandbox.exec("python train.py", { env: { MODEL_NAME: "gpt-tiny", EPOCHS: "50", BATCH_SIZE: "32", WANDB_API_KEY: process.env.WANDB_API_KEY!, },});Sandbox-level environment
Section titled “Sandbox-level environment”Set environment variables for the entire sandbox lifecycle:
const sandbox = await runra.sandboxes.create({ image: "node:22", env: { NODE_ENV: "production", DATABASE_URL: "postgres://...", // These are available to all subsequent exec() calls }, resources: { cpu: 2, memoryMb: 4096 },});
// No need to pass NODE_ENV againconst result = await sandbox.exec("node app.js");Secret management
Section titled “Secret management”Never hardcode secrets. Use runtime injection:
// ✅ Good: Secrets from environment or secret managerawait sandbox.exec("deploy.sh", { env: { CLOUDFLARE_API_TOKEN: await secrets.get("CLOUDFLARE_API_TOKEN"), GITHUB_TOKEN: await secrets.get("GITHUB_TOKEN"), },});
// ❌ Bad: Hardcoded secretsawait sandbox.exec("deploy.sh", { env: { CLOUDFLARE_API_TOKEN: "abc123-hardcoded-bad", },});Working directory
Section titled “Working directory”Specify the working directory for commands:
await sandbox.exec("git clone https://github.com/acme/app.git");await sandbox.exec("npm install", { cwd: "/workspace/app" });await sandbox.exec("npm test", { cwd: "/workspace/app" });The default working directory is /workspace. You can change it per-command or set a sandbox-level default:
const sandbox = await runra.sandboxes.create({ image: "node:22", workdir: "/workspace/my-project", // Default for all commands});Timeouts
Section titled “Timeouts”Set timeouts to prevent runaway commands:
// Per-command timeout (5 seconds)const result = await sandbox.exec("curl https://slow-api.example.com", { timeoutMs: 5_000,});
if (result.exitCode === null && result.signal === "SIGKILL") { console.log("Command timed out");}Timeout behavior
Section titled “Timeout behavior”When a timeout fires:
- The process inside the sandbox is sent
SIGTERM - If it doesn’t exit within 5 seconds,
SIGKILLis sent exitCodeisnullandsignalis the signal that killed it- The sandbox remains running — only the command is killed
Sandbox-level timeout
Section titled “Sandbox-level timeout”Set a maximum lifetime for the entire sandbox:
const sandbox = await runra.sandboxes.create({ image: "node:22", timeoutMs: 600_000, // Terminate sandbox after 10 minutes});Running scripts and files
Section titled “Running scripts and files”Execute a script file
Section titled “Execute a script file”// Write a scriptawait sandbox.files.write("/workspace/setup.sh", `#!/bin/bashset -enpm installnpm run buildnpm test`);
// Make it executable and runawait sandbox.exec("chmod +x /workspace/setup.sh");const result = await sandbox.exec("/workspace/setup.sh");Execute code in specific languages
Section titled “Execute code in specific languages”// Pythonawait sandbox.exec("python -c 'print(sum(range(100)))'");
await sandbox.exec('node -e "console.log(process.version)"');
// Shell pipelineconst result = await sandbox.exec("cat package.json | grep version | cut -d'\"' -f4");console.log(result.stdout.trim()); // e.g., "1.0.0"Background processes
Section titled “Background processes”Start background processes with &:
// Start a dev server in the backgroundawait sandbox.exec("npm run dev &");
// Wait for the server to be readyawait sandbox.exec("sleep 3 && curl -s http://localhost:3000/health");
// The server keeps running — you can make more exec() callsconst result = await sandbox.exec("curl -s http://localhost:3000/api/users");Managing background processes
Section titled “Managing background processes”// Find background processesconst ps = await sandbox.exec("ps aux");console.log(ps.stdout);
// Kill a specific processawait sandbox.exec("pkill -f 'node server.js'");
// Kill all background node processesawait sandbox.exec("pkill node");Error handling patterns
Section titled “Error handling patterns”Try/catch for known failures
Section titled “Try/catch for known failures”try { await sandbox.exec(`node -e "throw new Error('boom')"`);} catch (error) { // Non-zero exit codes don't throw by default // Only infrastructure errors throw console.error("Infrastructure error:", error.message);}Check exit codes explicitly
Section titled “Check exit codes explicitly”async function runOrThrow(sandbox: Sandbox, command: string) { const result = await sandbox.exec(command); if (result.exitCode !== 0) { throw new Error( `Command failed (exit ${result.exitCode}): ${command}\n${result.stderr}` ); } return result;}
// Usageawait runOrThrow(sandbox, "npm test"); // Throws if tests failRetry on transient failures
Section titled “Retry on transient failures”async function execWithRetry( sandbox: Sandbox, command: string, maxRetries = 3): Promise<ExecutionResult> { for (let i = 0; i < maxRetries; i++) { const result = await sandbox.exec(command); if (result.exitCode === 0) return result;
// Only retry on specific failures (e.g., network timeouts) if (result.stderr.includes("ETIMEDOUT") && i < maxRetries - 1) { console.warn(`Retrying (${i + 1}/${maxRetries}): ${command}`); await new Promise((r) => setTimeout(r, 2000)); continue; } return result; // Don't retry other failures } throw new Error(`Command failed after ${maxRetries} retries: ${command}`);}Command chaining
Section titled “Command chaining”Chain multiple commands together:
// Sequential commands (each waits for the previous)await sandbox.exec("git clone https://github.com/acme/app.git");await sandbox.exec("cd /workspace/app && npm install");const result = await sandbox.exec("cd /workspace/app && npm test");
// Or in a single shell call with &&const result = await sandbox.exec( "git clone https://github.com/acme/app.git && cd app && npm install && npm test");Conditional execution
Section titled “Conditional execution”// Run commands conditionally based on previous resultsconst check = await sandbox.exec("test -d /workspace/app");if (check.exitCode === 0) { await sandbox.exec("cd /workspace/app && git pull");} else { await sandbox.exec("git clone https://github.com/acme/app.git");}Next steps
Section titled “Next steps”- Exposing Ports — expose dev servers and web apps
- Observability — track all exec events
- SDK Usage — complete SDK reference