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";

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

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

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


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

No packages published

Contributors 4

  •  
  •  
  •  
  •