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.
dependencies, middleware, and input/output validationinit, ready, cooldown, disposeretry, timeout, circuitBreaker, cache, and rateLimitapp predictablyThe goal is simple: keep dependencies explicit, keep lifecycle predictable, and make your runtime easy to control in production and in tests.
Runner follows a simple support policy so teams can plan upgrades without guesswork.
6.x: actively maintained. New features, improvements, bug fixes, and documentation updates land here first.5.x: LTS through December 31, 2026. Critical fixes and important maintenance can continue there, but new development is focused on 6.x.If you are starting a new project, use 6.x.
If you are on 5.x, you have a stable upgrade window through the end of 2026.
See Support & Release Policy for the full versioning and support policy.
import { r, run } from "@bluelibs/runner";
const userCreated = r
.event<{ id: string; email: string }>("userCreated")
.build();
const userStore = r
.resource("userStore")
.init(async () => new Map<string, { id: string; email: string }>())
.build();
const createUser = r
.task<{ email: string }>("createUser")
.dependencies({ userStore, userCreated })
.run(async (input, { userStore, userCreated }) => {
const user = { id: "user-1", email: input.email };
userStore.set(user.id, user);
await userCreated(user);
return user;
})
.build();
const sendWelcomeEmail = r
.hook("sendWelcomeEmail")
.on(userCreated)
.run(async (event) => {
console.log(`Welcome ${event.data.email}`);
})
.build();
const app = r
.resource("app")
.register([userStore, createUser, sendWelcomeEmail])
.build();
const runtime = await run(app);
await runtime.runTask(createUser, { email: "ada@example.com" });
await runtime.dispose();
This example is intentionally runnable with only @bluelibs/runner, typescript, and tsx.
Note: User-defined ids are local ids. Prefer
createUser,userStore, andsendWelcomeEmail. Runner composes canonical ids such asapp.tasks.createUserat runtime.
| 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 |
| Compact Guide | Docs | Compact summary (<10,000 tokens) |
| Full Guide | Docs | Complete documentation (composed) |
| Support & Release Policy | Docs | Support windows and deprecation |
| Design Documents | Docs | Architecture notes and deep dives |
| Example: AWS Lambda Quickstart | Example | API Gateway + Lambda integration |
| Example: Express + OpenAPI + SQLite | Example | REST API with OpenAPI specification |
| Example: Fastify + MikroORM + PostgreSQL | Example | Full-stack application with ORM |
fetch runtime)| 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 AsyncLocalStorage; Bun/Deno may support it via the universal build when available |
Durable workflows (@bluelibs/runner/node) |
Full | None | None | Node-only module |
Remote Lanes client (createHttpClient) |
Full | Full | Full | Explicit universal client for fetch runtimes |
Remote Lanes server (@bluelibs/runner/node) |
Full | None | None | Exposes tasks/events over HTTP |
Use these minimums before starting:
| Requirement | Minimum | Notes |
|---|---|---|
| Node.js | 22.x+ |
Enforced by package.json#engines.node |
| TypeScript | 5.6+ (recommended) |
Required for typed DX and examples in this repository |
| Package manager | npm / pnpm / yarn / bun | Examples use npm, but any modern package manager works |
fetch runtime |
Built-in or polyfilled | Required for explicit remote lane clients (createHttpClient) |
If you use the Node-only package (@bluelibs/runner/node) for durable workflows or exposure, stay on a supported Node LTS line.
This page is the shortest path from "what is Runner?" to "I ran it once and I trust the shape of it."
New to Runner? Here's the absolute minimum you need to know:
init, ready, cooldown, dispose.app resource with .register([...]).run(app) which gives you runTask() and dispose() first, then more runtime helpers as you grow.This is the fastest way to run the TypeScript example at the top of this README.
22+, TypeScript 5.6+ recommended).npm i @bluelibs/runner
npm i -D typescript tsx
index.ts.npx tsx index.ts
What you now have: a working runtime, explicit dependency wiring, and the smallest useful Runner execution path.
Tip: User-defined ids are local ids. Use
createUseroruserStore, not dotted ids likeapp.tasks.createUser. Platform Note: Advanced features such as Durable Workflows and server-side Remote Lanes are Node-only.
You write local ids in definitions:
task("createUser")resource("userStore")event("userCreated")Runner composes canonical runtime ids from ownership:
app.tasks.createUserapp.userStoreapp.events.userCreatedPrefer references such as runTask(createUser, input) over string ids whenever you can.
@bluelibs/runner-dev gives you CLI scaffolding and runtime introspection.
npm install -g @bluelibs/runner-dev
# or
npx @bluelibs/runner-dev --help
# Scaffold a new Runner project
runner-dev new my-app --install
# Query tasks from a local TypeScript entry file (dry-run mode)
runner-dev query 'query { tasks { id } }' --entry-file ./src/main.ts
# Inspect a running app via GraphQL endpoint
ENDPOINT=http://localhost:1337/graphql runner-dev overview --details 10
For full CLI and Dev UI docs, see Runner Dev Tools.
This project is licensed under the MIT License. See LICENSE.md.