Sandbox

Run isolated sandboxes on Cloudflare, Vercel, Deno, Docker, or locally.

Sandbox runs named server-side handlers inside an isolated provider runtime. Sandbox fits work that needs filesystem, process, or network isolation without introducing a longer-lived workflow or a delivery queue.

ViteHub discovers sandboxes from server/sandboxes/**.

Define a sandbox with createSandbox(options?)(handler) or defineSandbox(handler, options?), then execute it with runSandbox().

Getting started

Install the package

Install @vitehub/sandbox and the provider SDK you want to use.

Terminal
pnpm add https://pkg.pr.new/nuxt-hub/agent/@vitehub/sandbox@main @cloudflare/sandbox

Configure a provider

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@vitehub/sandbox/nuxt'],
})

Define a sandbox

Create a file in server/sandboxes/**. The file name becomes the sandbox name.

server/sandboxes/release-notes.ts
import { createSandbox } from '@vitehub/sandbox'

type ReleaseNotesPayload = {
  notes?: unknown
}

export default createSandbox({
  timeout: 30_000,
})(async (payload?: ReleaseNotesPayload) => {
  const notes = typeof payload?.notes === 'string' ? payload.notes.trim() : ''
  const items = notes
    .split(/\n+/)
    .map(line => line.replace(/^[-*]\s*/, '').trim())
    .filter(Boolean)

  return {
    summary: items[0] || 'No notes provided.',
    items: items.slice(0, 3),
  }
})

Run the sandbox

Call the named sandbox from any server-side code. runSandbox() returns a result object, so check for errors before you return the value.

server/api/release-notes.post.ts
import { createError, readBody } from 'h3'
import { runSandbox } from '@vitehub/sandbox'

export default defineEventHandler(async (event) => {
  const body = await readBody<{ notes?: unknown }>(event)
  const result = await runSandbox('release-notes', body)

  if (result.isErr()) {
    throw createError({
      statusCode: 500,
      statusMessage: result.error.message,
      data: {
        code: result.error.code,
        provider: result.error.provider,
      },
    })
  }

  return result.value
})
Cloudflare Sandbox
Configure Cloudflare Sandbox on top of Durable Objects.
Vercel Sandbox
Configure Vercel Sandbox and run isolated sandboxes on Vercel.
Deno Sandbox
Configure Deno Sandbox and run isolated sandboxes on Deno Deploy.
Docker Sandbox
Configure Docker Sandbox and run isolated sandboxes locally.
Local Sandbox
Run sandboxes locally with OS-level isolation using platform primitives.

Public API

FunctionUse it for
createSandbox(options?)(handler)Register one named sandbox under the sandboxes directory.
defineSandbox(handler, options?)Compatibility wrapper for createSandbox(options?)(handler).
runSandbox(name, payload, { context? })Execute that sandbox from a route, task, or webhook.

Type reference

Handler signature

The handler receives an optional payload and an optional context object, and returns the result directly.

type SandboxHandler<TPayload, TResult> = (
  payload?: TPayload,
  context?: Record<string, unknown>,
) => TResult | Promise<TResult>

SandboxDefinitionOptions

The options object passed to createSandbox() or the second argument to defineSandbox() accepts portable options that work across all providers:

OptionTypeDescription
timeoutnumberMaximum execution time in milliseconds.
envRecord<string, string>Environment variables passed to the sandbox.
runtime{ command, args? }Custom runtime command for the sandbox process.
Provider-specific settings such as cpu, ports, or sandboxId belong in the top-level sandbox config in nitro.config.ts, not in the definition.

Result<T>

runSandbox() returns a Result<T> instead of throwing. Check the result before accessing the value.

Method / FieldTypeDescription
isOk()booleantrue when execution succeeded.
isErr()booleantrue when execution failed.
valueTThe handler return value. Only safe after isOk().
errorSandboxErrorError details with message, code, provider, and details.

How configuration works

Sandbox has two configuration layers:

  • Top-level sandbox config in nitro.config.ts selects the provider and sets app-wide defaults.
  • createSandbox(options?)(handler) configures one sandbox file with portable options such as timeout and env. defineSandbox(handler, options?) remains available as a compatibility wrapper.

runSandbox() is not configuration. It is the execution call, so that is where you pass the payload and optional per-request context.

nitro.config.ts
export default defineNitroConfig({
  sandbox: {
    provider: 'vercel',
  },
})
server/sandboxes/release-notes.ts
export default createSandbox({
  timeout: 30_000,
})(async (payload) => {
  return { ok: true }
})
Each provider adds its own runtime APIs and sub-features. Use the provider pages in the sidebar for SDK installation, platform setup, and provider-only options.