Functions
Overview
Section titled “Overview”Functions run your server-side code as bounded HTTP handlers: Request → Response. Every function receives a standard Web API request and returns a response—streaming included. There is no background execution, built-in retries, or cron scheduling inside Functions; use Jobs for durable work.
Three runtime adapters ship at v0:
- WASM — In-process via Wasmtime; sub-100ms cold starts when precompiled.
- Bun — TypeScript/JavaScript with a warm subprocess pool.
- Lambda — Remote AWS execution via Function URLs and the Lambda Web Adapter.
Deploy and promote are separate steps: push a bundle, verify it materializes, then promote to swap live traffic. This prevents broken builds from reaching production.
Key features
Section titled “Key features”- Web Standard contract —
fetch(req) → Response(Bun) or WASI HTTP (WASM). - Streaming responses — First-class; AI and SSE workloads supported from day one.
- Versioned bundles — Every deployment stored in Storage; rollback to any prior version.
- Per-function secrets — Encrypted environment variables injected at invoke time.
- Invoke policies — Restrict by method, path, time window, or custom rules.
- Unified observability —
X-Reactor-Function,X-Reactor-Cold-Start, andX-Reactor-Duration-Msheaders on every response.
Quickstart
Section titled “Quickstart”Create a Bun function, deploy a bundle, promote it, and invoke.
functions/hello/code/index.ts:
export default { async fetch(request: Request): Promise<Response> { const { name = 'World' } = await request.json().catch(() => ({})); return Response.json({ message: `Hello, ${name}!` }); },};reactor functions create hello --runtime bunreactor functions deploy hello --dir ./functions/helloreactor functions promote helloreactor functions invoke hello --json '{"name":"Reactor"}'import { createClient } from '@reactor/client';
const reactor = createClient({ url: process.env.REACTOR_URL! });await reactor.auth.signInWithPassword({ email, password });reactor.auth.setOrg('acme');
await reactor.functions.create({ name: 'hello', runtime: 'bun' });await reactor.functions.deploy('hello', { directory: './functions/hello' });await reactor.functions.promote('hello');
const res = await reactor.functions.invoke('hello', { method: 'POST', body: JSON.stringify({ name: 'Reactor' }),});console.log(await res.json());# Invoke (after deploy + promote via admin API)curl -s -X POST "$REACTOR_URL/fn/v1/hello" \ -H "Authorization: Bearer $REACTOR_TOKEN" \ -H "X-Reactor-Org: acme" \ -H "Content-Type: application/json" \ -d '{"name":"Reactor"}'How-to guides
Section titled “How-to guides”Deploy with environment secrets
Section titled “Deploy with environment secrets”Secrets are encrypted at rest and never returned by the admin API.
reactor functions env set hello STRIPE_SECRET_KEY --secretreactor functions env set hello STRIPE_PUBLIC_KEY sk_live_...reactor functions deploy hello --dir ./functions/helloreactor functions promote helloawait reactor.functions.env.set('hello', 'STRIPE_SECRET_KEY', { value: process.env.STRIPE_SECRET_KEY!, secret: true,});curl -s -X PUT "$REACTOR_URL/fn/v1/_admin/functions/hello/env/STRIPE_SECRET_KEY" \ -H "Authorization: Bearer $REACTOR_TOKEN" \ -H "X-Reactor-Org: acme" \ -H "Content-Type: application/json" \ -d '{"value":"sk_live_...","secret":true}'Reference secrets in your manifest:
{ "name": "hello", "runtime": "bun", "entrypoint": "code/index.ts", "env_keys": ["STRIPE_PUBLIC_KEY"], "secret_keys": ["STRIPE_SECRET_KEY"]}Stream a Server-Sent Events response
Section titled “Stream a Server-Sent Events response”// Inside your function handlerexport default { async fetch(): Promise<Response> { const stream = new ReadableStream({ async start(controller) { for (let i = 0; i < 10; i++) { controller.enqueue(`data: ${JSON.stringify({ chunk: i })}\n\n`); await new Promise((r) => setTimeout(r, 200)); } controller.close(); }, }); return new Response(stream, { headers: { 'Content-Type': 'text/event-stream' }, }); },};curl -N -X POST "$REACTOR_URL/fn/v1/stream-demo" \ -H "Authorization: Bearer $REACTOR_TOKEN" \ -H "X-Reactor-Org: acme"Roll back to a previous deployment
Section titled “Roll back to a previous deployment”reactor functions deployments list helloreactor functions rollback hello --to-deployment dep_01HZ...const deployments = await reactor.functions.deployments.list('hello');await reactor.functions.rollback('hello', { toDeploymentId: deployments[1].id,});curl -s -X POST "$REACTOR_URL/fn/v1/_admin/functions/hello/rollback" \ -H "Authorization: Bearer $REACTOR_TOKEN" \ -H "X-Reactor-Org: acme" \ -H "Content-Type: application/json" \ -d '{"to_deployment_id":"dep_01HZ..."}'Configuration
Section titled “Configuration”[functions]workdir = "./.reactor/functions"data_key = "base64-32-byte-key"bundle_max_bytes = 52428800 # 50 MiBinvoke_default_timeout_ms = 30000invoke_max_timeout_ms = 300000bun_idle_ttl_secs = 300bun_max_instances_per_fn = 8
# Runtimes to enable (comma-separated: wasm,bun,lambda)runtimes = ["wasm", "bun"]
[functions.storage]url = "http://localhost:8003"api_key = "storage-api-key-for-system-bucket"
[functions.lambda]region = "us-east-1"role_arn = "arn:aws:iam::123456789012:role/reactor-lambda"bundle_s3_bucket = "reactor-function-bundles"lwa_layer_arn = "arn:aws:lambda:us-east-1:753240598075:layer:LambdaAdapterLayerX86:..."Limits and quotas
Section titled “Limits and quotas”| Limit | WASM | Bun | Lambda |
|---|---|---|---|
| Default timeout | 30s | 30s | 30s (max 900s) |
| Max timeout | 300s | 300s | 900s |
| Memory range | 32–1024 MB | 64–2048 MB | 128–10240 MB |
| Bundle size | 50 MiB | 50 MiB | 50 MiB |
| Cold start (p50) | ~50ms | ~200ms | ~300ms (no PC) |
| Warm latency (p50) | ~5ms | ~15ms | ~30ms |
| Max concurrency | Per manifest | Per manifest | Reserved concurrency optional |
Manifest concurrency block:
{ "concurrency": { "min_instances": 0, "max_concurrency": 50 }}When concurrency cap is hit, Reactor returns 429 too_many_requests with Retry-After: 1.
API and SDK links
Section titled “API and SDK links”- HTTP base path:
/fn/v1/ - Admin base path:
/fn/v1/_admin/ - OpenAPI reference: Functions API
- JavaScript SDK:
reactor.functions - CLI:
reactor functions
| Method | Path | Description |
|---|---|---|
* | /fn/v1/{name} | Invoke function |
* | /fn/v1/{name}/{*sub} | Invoke with sub-path |
POST | /fn/v1/_admin/functions | Create function |
POST | /fn/v1/_admin/functions/{name}/deployments | Upload bundle |
POST | /fn/v1/_admin/functions/{name}/promote | Swap live traffic |
GET | /fn/v1/_admin/functions/{name}/logs | Stream logs (SSE) |
Troubleshooting
Section titled “Troubleshooting”503 deployment_not_ready
Section titled “503 deployment_not_ready”The deployment is still materializing or failed. Check deployment status and logs before promoting again.
reactor functions deployments list helloreactor functions logs hello --follow408 function_timeout
Section titled “408 function_timeout”The handler exceeded limits.timeout_ms. Optimize long operations or move them to a Job. For Lambda, also verify the AWS function timeout matches.
429 too_many_requests
Section titled “429 too_many_requests”Concurrency cap reached. Increase max_concurrency in the manifest or implement client-side backoff using the Retry-After header.
500 function_crashed
Section titled “500 function_crashed”Your handler threw an uncaught exception. Check function logs—the platform response includes deployment_id and duration_ms in error details.
manifest_invalid on deploy
Section titled “manifest_invalid on deploy”Ensure env_keys and secret_keys in the manifest exist in function env before deploying. The server recomputes bundle_sha256—client-provided hash must match.