Skip to main content
New to Runner? This guide gets you to a working example as quickly as possible.

What you’ll build

You’ll create a simple task that greets users, demonstrating:
  • Task definition with dependencies
  • Resource lifecycle (init/dispose)
  • Middleware (automatic retries)
  • Input validation with Zod
  • Running your app

Installation

1

Install dependencies

Install Runner and Zod for schema validation:
npm install @bluelibs/runner zod
npm install -D typescript tsx
This guide assumes Node.js 18+ and TypeScript 5.6+. See Installation for detailed requirements.
2

Create your first task

Create a file called index.ts and add the following code:
index.ts
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: "[email protected]" });
// await runtime.dispose() when you are done.
3

Run your app

Execute your TypeScript file:
npx tsx index.ts
You should see output like:
Sending welcome email to [email protected]
That’s it! You now have a working Runner application.

What just happened?

Let’s break down what you built:

Resources (singletons with lifecycle)

const db = r
  .resource("app.db")
  .init(async () => {
    const conn = await postgres.connect(process.env.DB_URL);
    return conn;
  })
  .build();
Resources are singletons with init and dispose lifecycle methods. They’re perfect for databases, HTTP servers, or anything that needs setup and teardown.

Tasks (business logic with DI)

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();
Tasks are async functions with:
  • Explicit dependencies: dependencies({ db, mailer }) injects what the task needs
  • Middleware: Add cross-cutting concerns like retries, timeouts, or caching
  • Validation: Input and output schemas ensure type safety at runtime
  • Type safety: Full TypeScript inference throughout

App composition

const app = r
  .resource("app")
  .register([db, mailer, createUser])
  .build();
The root resource composes everything together. Runner wires all dependencies automatically.

Runtime

const runtime = await run(app);
await runtime.runTask(createUser, { name: "Ada", email: "[email protected]" });
The run() function initializes all resources, wires dependencies, and returns a runtime object with methods like runTask, emitEvent, and dispose.

Next steps

Tasks

Learn more about defining and composing tasks

Resources

Understand resource lifecycle and patterns

Middleware

Add reliability with built-in middleware

Testing

Write tests for your Runner apps
Want to see real-world examples? Check out the Express + OpenAPI + SQLite and Fastify + MikroORM + PostgreSQL examples in the GitHub repository.

Build docs developers (and LLMs) love