Skip to content

The recommended way to run scripts on Hoody. Write a TypeScript/JavaScript function in a file. That’s it. You now have an HTTP endpoint — complete with automatic routing, JSON serialization, dependency installation, and production-grade execution. No Express. No Fastify. No webserver configuration. No package.json. Just write code in files, and they become URLs.

This is what “everything is HTTP” means in practice. Your code IS the API.


Everything in Hoody Exec revolves around choosing the right execution mode. This one decision changes everything about how your code runs.

FeatureWorker ModeServerless Mode
StatePersistent shared objectNone (fresh each time)
WebSocketSupportedNot available
ConcurrencyUnlimited (handle in code)Configurable via @concurrent
StartupOnce (fast subsequent requests)Per request (slight overhead)
MemoryHigher (persistent VM)Lower (ephemeral)
Use CaseReal-time, stateful APIsWebhooks, isolated tasks

Worker Mode (// @mode worker) — Think: long-running Node.js server that never restarts. Persistent VM, shared state across requests, WebSocket support, zero cold start.

Serverless Mode (// @mode serverless or omit) — Think: AWS Lambda, Vercel Functions. Fresh VM per request, complete isolation, configurable concurrency.

See Execution Modes for the complete deep dive with real-world examples.


  • File = API — Create file → instant HTTP endpoint (no server config)
  • Two Modes — Worker (persistent) or Serverless (isolated)
  • Magic Comments — Configure with // @mode worker, // @cors *, // @timeout 5000
  • File-Based Routingapi/users/[id].ts/api/users/123 with dynamic parameters
  • Powered by Bun — Modern JavaScript runtime (faster than Node.js)
  • AI Code Generation — Write // @ai true → get AI helpers injected automatically
  • Auto-Install Dependencies — Use require('axios') → automatically installed (no package.json)
  • Templates — Scaffold from built-in or custom templates
  • Code Validation — TypeScript checking, syntax validation, dependency analysis
  • Shared State — In-memory KV store across requests (worker mode only)
  • WebSocket Support — Real-time bidirectional communication (worker mode only)
  • Monitoring — Performance metrics, log streaming, cache stats

Create scripts/1/api/hello.ts:

// @mode serverless
// @cors reflective
// @timeout 5000
return {
message: 'Hello from Hoody Exec!',
timestamp: new Date().toISOString(),
method: metadata.method,
ip: metadata.clientIp
};

That’s it. It’s now live at:

https://PROJECT_ID-CONTAINER_ID-exec-1.SERVER.containers.hoody.icu/api/hello

No imports. No exports. No configuration. The parameters (metadata, req, res, shared) are automatically injected.


Every Hoody Exec instance is accessible via a unique hostname:

{projectId}-{containerId}-exec-{execId}.{server}.containers.hoody.icu
ComponentDescriptionExample
projectIdYour project IDabc123
containerIdContainer IDdef456
execIdExec instance identifier1, 2, test
serverServer locationus1, eu2

The exec ID determines which script directory is used:

  • exec-1 serves scripts from scripts/1/
  • exec-2 serves scripts from scripts/2/
  • exec-test serves scripts from scripts/test/

You can run multiple exec instances on a single container, each with its own scripts, routing, and shared state. Subdomains resolve automatically — create a new exec ID and it’s immediately routable.

Use the exec list endpoint to see which exec instances are available:

Terminal window
# List all exec instance IDs
hoody exec namespaces list

Example response:

{
"execIds": [
{ "id": "1", "type": "custom", "files": 4 },
{ "id": "2", "type": "custom", "files": 1 }
],
"total": 2,
"summary": { "sdk": 0, "custom": 2 }
}

To list scripts for a specific exec instance:

Terminal window
# List all scripts in the current exec instance
hoody exec scripts list-user

Since every script is an HTTP endpoint, you can call any script from any other script using fetch():

scripts/1/api/aggregate.ts
// @mode serverless
// Call other exec scripts by their URL path
const news = await fetch("/api/hackernews");
const weather = await fetch("/api/weather");
const [newsData, weatherData] = await Promise.all([
news.json(),
weather.json()
]);
return { news: newsData, weather: weatherData };

Relative paths like /api/hackernews resolve to the same exec instance. To call scripts on a different instance or container, use the full hostname:

// Call a script on exec instance 2
const res = await fetch("https://PROJECT-CONTAINER-exec-2.SERVER.containers.hoody.icu/api/users");
// Call a script on a different container
const res2 = await fetch("https://PROJECT-OTHER_CONTAINER-exec-1.SERVER.containers.hoody.icu/reports/daily");

Get your first script running in three steps:

1. Write — Create a script file:

scripts/1/hello.js
// @mode serverless
return { message: 'Hello, world!', time: Date.now() };

Or create it programmatically:

Terminal window
# Write a script to the exec instance
hoody exec scripts write --path "hello.js" \
--content "// @mode serverless\nreturn { message: 'Hello, world!' };" \
--create-dirs

2. Execute — Access your script via its URL:

Terminal window
curl "https://PROJECT-CONTAINER-exec-1.SERVER.containers.hoody.icu/hello"

3. Verify — Check the response and logs:

{ "message": "Hello, world!", "time": 1708700000000 }

Stream logs in real time to debug:

Terminal window
# Stream logs from the exec instance
hoody exec logs stream --file "api/hello.ts"

All endpoints accessed relative to your Exec instance:

https://PROJECT_ID-CONTAINER_ID-exec-1.SERVER.containers.hoody.icu

Core Execution:

Script Management:

Templates:

Validation:

Dependencies:

Routing:

Package Management:

Magic Comments API:

State & Cache:

Logs:

Monitoring:

System:

User OpenAPI:

SDK Management:

Custom Templates:

Bundled Dependencies:


Skip Express/Fastify setup — write functions in files, they’re instantly HTTP endpoints. Worker mode for performance, serverless for isolation.

WebSocket chat servers, live dashboards, SSE streams, collaborative tools — worker mode’s persistent VM handles connections efficiently with shared state.

Stripe, GitHub, Slack webhooks — serverless isolation prevents cross-contamination, @concurrent false ensures serial processing for consistency.

Intercept and control AI requests via MITM proxy. Add safety checks, modify prompts, track usage. See Hoody AI Intercept & Control.

Register hoody-exec scripts as MITM handlers for any container service (terminal, files, curl, …) directly in your proxy permissions document. The Hoody Proxy dispatches matching traffic through your hook with the real client IP preserved. See Proxy Hooks.

Admin dashboards, data migration scripts, reporting endpoints — choose worker for speed with caching or serverless for isolation and safety.

Track user sessions, implement rate limiting, maintain connection pools — shared state persists across requests with zero overhead.

Rapid iteration with magic comments, test ideas without deployment complexity, AI-generate boilerplate instantly — from idea to API in seconds.


Worker mode when you need state, WebSocket, or handle high request volume with caching. Serverless mode when you need isolation, process webhooks, or have sporadic traffic.

Always declare @mode first, set reasonable timeouts to prevent hangs, use @cors reflective for development, enable appropriate logging level for debugging. See Magic Comments Reference.

Never run untrusted code in worker mode (shared state contamination risk), deploy behind authentication for sensitive operations, use container firewall for production, validate all user input.

Use shared object for in-memory cache only, clean up old state periodically to prevent memory leaks, understand state lost on restart, use SQLite for data that must survive restarts.

Use @concurrent 5 to limit parallel executions and prevent overload, set @concurrent false for serial processing (webhooks), monitor queue depth via stats API.

Let auto-install handle common packages (zero config), pin versions in production for stability via package.json if needed, test dependencies before deploying, monitor node_modules size growth.

Use worker mode for frequently-called endpoints (zero cold start), monitor cache hit rates (should be >95%), keep scripts small and focused (under 200 lines), implement timeout limits to prevent hangs.


Q: When should I use worker vs serverless mode? Use worker for WebSocket, stateful apps, high-traffic APIs, session management, rate limiting. Use serverless for webhooks, isolated tasks, untrusted code, sporadic traffic, stateless operations. See Execution Modes for the full comparison.

Q: Can serverless mode use WebSocket? No — WebSocket requires persistent connection handling in a persistent VM. Only worker mode supports WebSocket.

Q: What happens to shared state on restart? Lost completely. shared is in-memory only. Use SQLite (hoody-sqlite service) or external database for data that must survive restarts.

Q: How does concurrency work in worker mode? Unlimited — your code handles all concurrent requests in the same VM. Manage concurrency yourself via semaphores or queues if needed. Serverless mode uses @concurrent to limit.

Q: Can I mix worker and serverless scripts? Yes — each script declares its own mode independently. Worker scripts at /api/ws.ts can coexist with serverless scripts at /webhooks/stripe.ts.

Q: How do magic comments work? Parsed at script load time. Configure script behavior without code changes. Validated via validation API. Take precedence over defaults. Change comment, behavior changes. See Magic Comments.

Q: Can I use TypeScript? Yes — .ts files automatically transpiled by Bun. Full TypeScript validation available via validation endpoints. Zero config needed.

Q: How does auto-install work? Detects require() calls, checks if module installed, runs npm install automatically, caches install status, uses latest versions (or pin in package.json).

Q: Do I need to manage a web server? No — that’s the point. You write functions in files, Hoody Exec IS the web server. No Express, no Koa, no configuration. The file system IS your routing configuration.


Cause: No script file matches URL path. Solution: Check file exists at /hoody/storage/hoody-exec/scripts/1/path/to/script.ts, verify filename matches route exactly, use route validation API to test.

Cause: Comments not at top of file or syntax error. Solution: Place magic comments before ANY code (even before imports), use validation endpoint to parse comments, check exact syntax (space after //), verify comment name spelling. See Magic Comments.

Cause: Using serverless mode or server restarted. Solution: Must use // @mode worker for shared state. State is in-memory only (lost on restart). Use SQLite service for persistence. See Execution Modes.

Cause: Missing magic comments or wrong mode. Solution: Must have both // @mode worker AND // @websocket. Worker mode required — serverless cannot do WebSocket.

Cause: Missing CORS magic comments. Solution: Add // @cors reflective for development, // @cors * for testing, specific origin for production (// @cors https://app.com).

Cause: Long-running operation exceeds timeout. Solution: Add // @timeout 60000 to increase limit, use // @timeout 0 for unlimited (risky), optimize slow operations, consider async patterns.

Cause: @concurrent limit reached, requests queuing. Solution: Increase limit (// @concurrent 10), optimize script performance, consider worker mode for high traffic, monitor queue depth.

Cause: Installation failed or network issue. Solution: Check network connectivity, verify module exists on npm, check logs for install errors, manually install if needed, check module name spelling.