Skip to content

Getting started

This guide gets the runtime running locally and serves a tiny app from a worker. You’ll need Bun 1.3+ installed.

  1. Clone and install:

    Terminal window
    git clone https://github.com/djalmajr/buntime.git
    cd buntime
    bun install
  2. Start the full dev stack — runtime, the core plugins, and the operator panel (cpanel) — from the repo root:

    Terminal window
    bun dev

    This runs the runtime with --watch. Use bun --watch, never bun --hot: hot mode breaks timers/cron and leaks port bindings.

  3. Check it’s alive:

    Terminal window
    curl http://localhost:8000/api/health

A “worker app” is just a directory with an entrypoint. The runtime discovers it from the directories listed in RUNTIME_WORKER_DIRS (PATH-style, separated by :).

  1. Create an app directory. Versioned, flat layout is the simplest:

    • Directoryapps/
      • Directoryhello@1.0.0/
        • index.ts
        • manifest.yaml
  2. Write the entrypoint. A worker exports a default object — a fetch handler is the simplest form:

    // apps/hello@1.0.0/index.ts
    export default {
    fetch(req: Request) {
    const url = new URL(req.url);
    return Response.json({ hello: "world", path: url.pathname });
    },
    };
  3. (Optional) Describe how the worker runs. Without a manifest the defaults apply (ephemeral discovery, 30s timeout):

    # apps/hello@1.0.0/manifest.yaml
    entrypoint: index.ts
    ttl: 0 # 0 = ephemeral (spawned per request); >0 keeps it warm
    timeout: 30s
    maxRequests: 1000
  4. Point the runtime at the directory and start it:

    Terminal window
    RUNTIME_WORKER_DIRS=./apps bun --watch apps/runtime/src/index.ts
  5. Call your app. An unscoped worker named hello is served at /hello/:

    Terminal window
    curl http://localhost:8000/hello/
    # {"hello":"world","path":"/"}

The ttl field defines the worker’s personality:

Spawned for each request and discarded afterward. Higher per-request latency, zero idle cost. Best for stateless, lambda-style handlers. Concurrency is bounded by RUNTIME_EPHEMERAL_CONCURRENCY (default 2); overflow queues up to RUNTIME_EPHEMERAL_QUEUE_LIMIT (default 100), then returns 503.

A worker’s default export can be a fetch handler, a routes object, or you can ship an index.html for a static SPA:

export default {
fetch(req: Request) {
return new Response("ok");
},
};