Build apps from tasks and resources with explicit dependencies, predictable lifecycle, and first-class testing
Runner is a TypeScript-first toolkit for building an app out of small, typed building blocks. You can find more details and a visual overview at runner.bluelibs.com.
- Tasks: async functions with explicit
dependencies, middleware, and input/output validation - Resources: singletons with
init/disposelifecycle (databases, clients, servers, caches) - Reliability Middleware: built-in
retry,timeout,circuitBreaker,cache, andrateLimit - HTTP Tunnels: cross-process execution (the "Distributed Monolith") with zero call-site changes
- Durable Workflows: persistent, crash-recoverable async logic for Node.js
- Events & hooks: typed signals and subscribers for decoupling
- Runtime control: run, observe, test, and dispose your
apppredictably
The goal is simple: keep dependencies explicit, keep lifecycle predictable, and make your runtime easy to control in production and in tests.
import { r, run, globals } from "@bluelibs/runner";
import { z } from "zod";
const db = r
.resource("app.db")
.init(async () => ({
users: {
insert: async (input: { name: string; email: string }) => ({
id: "user-1",
...input,
}),
},
}))
.build();
const mailer = r
.resource("app.mailer")
.init(async () => ({
sendWelcome: async (email: string) => {
console.log(`Sending welcome email to ${email}`);
},
}))
.build();
// Define a task with dependencies, middleware, and zod validation
const createUser = r
.task("users.create")
.dependencies({ db, mailer })
.middleware([globals.middleware.task.retry.with({ attempts: 3 })])
.inputSchema(z.object({ name: z.string(), email: z.string().email() }))
.run(async (input, { db, mailer }) => {
const user = await db.users.insert(input);
await mailer.sendWelcome(user.email);
return user;
})
.build();
// Compose resources and run your application
const app = r.resource("app").register([db, mailer, createUser]).build();
const runtime = await run(app);
await runtime.runTask(createUser, { name: "Ada", email: "ada@example.com" });
// await runtime.dispose() when you are done.| Resource | Type | Description |
|---|---|---|
| Official Website & Documentation | Website | Overview and features |
| GitHub Repository | GitHub | Source code, issues, and releases |
| Runner Dev Tools | GitHub | Development CLI and tooling |
| API Documentation | Docs | TypeDoc-generated reference |
| AI-Friendly Docs | Docs | Compact summary (<5000 tokens) |
| Full Guide | Docs | Complete documentation (composed) |
| Design Documents | Docs | Architecture notes and deep dives |
| Example: Express + OpenAPI + SQLite | Example | REST API with OpenAPI specification |
| Example: Fastify + MikroORM + PostgreSQL | Example | Full-stack application with ORM |
- New to Runner: Start with Your First 5 Minutes
- Prefer an end-to-end example: Jump to Quick Start or the Real-World Example
- Need Node-only capabilities: See Durable Workflows
- Need remote execution: See HTTP Tunnels (expose from Node.js, call from any
fetchruntime) - Care about portability: Read Multi-Platform Architecture
- Want the complete guide: Read FULL_GUIDE.md
- Want the short version: Read AI.md
| Capability | Node.js | Browser | Edge | Notes |
|---|---|---|---|---|
| Core runtime (tasks/resources/middleware/events/hooks) | Full | Full | Full | Platform adapters hide runtime differences |
Async Context (r.asyncContext) |
Full | None | None | Requires Node.js AsyncLocalStorage |
Durable workflows (@bluelibs/runner/node) |
Full | None | None | Node-only module |
Tunnels client (createExposureFetch) |
Full | Full | Full | Requires fetch |
Tunnels server (@bluelibs/runner/node) |
Full | None | None | Exposes tasks/events over HTTP |
New to Runner? Here's the absolute minimum you need to know:
- Tasks are your business logic functions (with dependencies and middleware)
- Resources are shared services (database, config, clients) with lifecycle (
init/dispose) - You compose everything under an
appresource with.register([...]) - You run it with
run(app)which gives yourunTask()anddispose()
That's it. Now let's get you to a first successful run.
This is the fastest way to run the TypeScript example at the top of this README:
- Install dependencies:
npm i @bluelibs/runner zod
npm i -D typescript tsx- Copy the example into
index.ts - Run it:
npx tsx index.tsThat’s it! You now have a working Runtime and you can execute tasks with runtime.runTask(...).
Tip: If you prefer an end-to-end example with HTTP, OpenAPI, and persistence, jump to the examples below.
- Complete guide: Read FULL_GUIDE.md (the full reference, composed from
guide-units/) - Popular guide sections:
- API reference: Browse the TypeDoc documentation
- Token-friendly overview: Read AI.md
- Node-only features:
- Multi-platform architecture: Read MULTI_PLATFORM.md
This project is licensed under the MIT License - see LICENSE.md.