Skip to content

cesarecaoduro/vercel-sandbox-pg

Repository files navigation

vercel-sandbox

JSON-config-driven runner for Vercel Sandbox microVMs. Define your setup and run steps in a JSON file, and the runner handles snapshot caching, cost tracking, and artifact downloads.

Quick start

pnpm install
vercel link && vercel env pull   # creates .env.local with OIDC credentials

# Run a config
node --env-file .env.local --experimental-strip-types ./run-sandbox.ts opencode-sandbox.json

Project structure

├── sandbox-utils.ts          # Core library: snapshot management, cost tracking, orchestrator
├── run-sandbox.ts            # CLI — takes any JSON config as argument
├── opencode-sandbox.json     # Config: OpenCode CLI + OpenCode SDK
└── scripts/                  # Script files referenced by configs
    └── verify-opencode.mjs

JSON config schema

Each config file defines a sandbox and an ordered list of steps:

{
  "label": "my-sandbox",       // snapshot label (used for caching)
  "vcpus": 2,                  // CPU cores (default: 2)
  "timeout": "10m",            // ms-parseable duration (default: "10m")
  "runtime": "node22",         // "node22", "node24", "python3.13" (default: "node22")
  "steps": [ /* ... */ ],      // executed in order
  "download": [ /* ... */ ]    // optional artifact downloads
}

Step types

Command step

Runs a shell command inside the sandbox.

{
  "type": "command",
  "name": "Install CLI",          // display name for logging
  "phase": "setup",              // "setup" or "run"
  "cmd": "npm",
  "args": ["install", "-g", "my-package"],
  "sudo": true,                  // optional
  "env": {                       // optional — "$VAR" resolves from process.env
    "API_KEY": "$MY_API_KEY"
  }
}

Script step

Uploads and runs a script file inside the sandbox. You can reference a local file or provide inline content:

// Reference a file (recommended)
{
  "type": "script",
  "name": "Verify SDK",
  "phase": "run",
  "file": "scripts/verify.mjs"
}

// Inline script (useful for one-liners)
{
  "type": "script",
  "name": "Quick check",
  "phase": "run",
  "script": "console.log('hello from sandbox');",
  "filename": "check.mjs"       // optional remote filename
}

When using file, the remote filename defaults to the file's basename. Both .mjs, .ts, and .py files work depending on the sandbox runtime.

Phases

  • setup — runs only on fresh sandbox creation. Skipped when restoring from a cached snapshot. The step name is tracked in the snapshot's installed-packages list.
  • run — always executes, regardless of snapshot state.

Artifact downloads

Download files from the sandbox to your local machine after all steps complete:

{
  "download": [
    {
      "remotePath": "/vercel/sandbox/output.md",
      "localPath": "./output/output.md"
    }
  ]
}

Environment variable resolution

Any env value prefixed with $ is resolved from process.env at runtime:

"env": { "API_KEY": "$MY_API_KEY" }
// resolves to process.env.MY_API_KEY (or "" if unset)

Execution flow

run-sandbox.ts my-config.json
  → Parse JSON config
  → Start cost tracker
  → Create sandbox (or restore from cached snapshot)
  → Iterate steps[] in order:
      [setup + fresh]    → execute, track in installed packages
      [setup + snapshot] → skip (log message)
      [run]              → always execute
  → Download artifacts
  → [fresh] Create snapshot for next run / [snapshot] Stop sandbox
  → Print cost summary

Prerequisites

  • Node.js v22+
  • A Vercel account with a linked project
  • pnpm (or npm)

Creating a custom config

  1. Create a JSON file following the schema above
  2. Add any script files your steps reference under scripts/ (or anywhere)
  3. Run it:
node --env-file .env.local --experimental-strip-types ./run-sandbox.ts my-config.json

Sandbox defaults

Option Default Notes
runtime node22 Available: node24, node22, python3.13
timeout 10m Max: 45min (Hobby), 5h (Pro/Enterprise)
vcpus 2 CPU cores allocated to the VM

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Contributors 2

  •  
  •