Skip to content

bluelibs/runner

BlueLibs Runner

Explicit TypeScript Dependency Injection Toolkit

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/dispose lifecycle (databases, clients, servers, caches)
  • Reliability Middleware: built-in retry, timeout, circuitBreaker, cache, and rateLimit
  • 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 app predictably

The goal is simple: keep dependencies explicit, keep lifecycle predictable, and make your runtime easy to control in production and in tests.

Build Status Coverage 100% is enforced Docs npm version npm downloads

import { r, run, globals } from "@bluelibs/runner";
import { z } from "zod";

// resources are singletons with lifecycle management and async construction
const db = r
  .resource("app.db")
  .init(async () => {
    const conn = await postgres.connect(process.env.DB_URL);
    return conn;
  })
  .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({ retries: 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") // top-level app resource
  .register([db, mailer, createUser]) // register all elements
  .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)
Support & Release Policy Docs Support windows and deprecation
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

Community & Policies

Choose Your Path

Platform Support (Quick Summary)

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 (createHttpClient) Full Full Full Requires fetch
Tunnels server (@bluelibs/runner/node) Full None None Exposes tasks/events over HTTP

Prerequisites

Use these minimums before starting:

Requirement Minimum Notes
Node.js 18.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 tunnel clients (createHttpClient, universal HTTP client)

If you use the Node-only package (@bluelibs/runner/node) for durable workflows or exposure, stay on a supported Node LTS line.


Your First 5 Minutes

New to Runner? Here's the absolute minimum you need to know:

  1. Tasks are your business logic functions (with dependencies and middleware)
  2. Resources are shared services (database, config, clients) with lifecycle (init / dispose)
  3. You compose everything under an app resource with .register([...])
  4. You run it with run(app) which gives you runTask() and dispose()

That's it. Now let's get you to a first successful run.


Quick Start

This is the fastest way to run the TypeScript example at the top of this README:

  1. Confirm prerequisites from Prerequisites (Node 18+, TypeScript 5.6+ recommended)

  2. Install dependencies:

npm i @bluelibs/runner zod
npm i -D typescript tsx
  1. Copy the example into index.ts
  2. Run it:
npx tsx index.ts

That'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.


Runner Dev Tools Quick Start

@bluelibs/runner-dev gives you CLI scaffolding and runtime introspection.

  1. Install (or run without install):
npm install -g @bluelibs/runner-dev
# or
npx @bluelibs/runner-dev --help
  1. Three common commands:
# 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.


Real-World Examples


Where To Go Next


License

This project is licensed under the MIT License - see LICENSE.md.

About

Modular and functional approach to building large scale apps.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors