Skip to main content

Overview

The run() function is the entry point for starting your Runner application. It initializes a resource (and all its dependencies), manages the lifecycle, and returns a runtime instance for executing tasks and emitting events.
import { r, run } from "@bluelibs/runner";

const app = r.resource("app")
  .register([myTask, myService])
  .build();

const runtime = await run(app);
await runtime.runTask(myTask, { name: "Ada" });
await runtime.dispose();

Signature

async function run<C, V extends Promise<any>>(
  resourceOrResourceWithConfig:
    | IResourceWithConfig<C, V>
    | IResource<void, V, any, any>
    | IResource<{ [K in any]?: any }, V, any, any>,
  options?: RunOptions
): Promise<RunResult<V extends Promise<infer U> ? U : V>>

Parameters

resourceOrResourceWithConfig
IResource | IResourceWithConfig
required
The resource to run, optionally with configuration.Pass without config:
const runtime = await run(app);
Pass with config:
const runtime = await run(app.with({ port: 3000 }));
options
RunOptions
Configuration options for the runtime.

Returns

runtime
RunResult<V>
A runtime instance providing access to:
  • Task execution via runTask()
  • Event emission via emitEvent()
  • Resource access via getResourceValue() / getLazyResourceValue()
  • Root access via getRootValue(), getRootConfig(), getRootId()
  • Lifecycle management via dispose()
See Runtime API for details.

Examples

Basic Usage

const app = r.resource("app")
  .register([greetTask])
  .build();

const runtime = await run(app);
const greeting = await runtime.runTask(greetTask, { name: "World" });
console.log(greeting); // "Hello, World!"
await runtime.dispose();

With Configuration

const server = r.resource("server")
  .configSchema<{ port: number }>({ parse: (v) => v })
  .init(({ config }) => {
    return startServer(config.port);
  })
  .build();

const runtime = await run(server.with({ port: 3000 }));

With Options

const runtime = await run(app, {
  logs: {
    printThreshold: "debug",
    printStrategy: "json",
  },
  lazy: true,
  initMode: "parallel",
});

Dry Run (Testing)

// Validate setup without running
const runtime = await run(app, { dryRun: true });
// No resources initialized, no events emitted
await runtime.dispose();

Custom Error Handling

const runtime = await run(app, {
  onUnhandledError: async (error, context) => {
    await reportToSentry(error);
    console.error("Unhandled error:", error);
  },
});

Lifecycle

When you call run(), the following happens:
  1. Registration Phase: All resources, tasks, events, hooks, and middleware are registered
  2. Validation Phase: Dependency graph and event emission graph are validated
  3. Override Processing: Any overrides are applied
  4. Listener Attachment: Event hooks are attached to their events
  5. Dependency Computation: Dependency injection is resolved
  6. Resource Initialization: Resources are initialized (sequentially or in parallel)
  7. Ready Event: globals.events.ready is emitted
  8. Runtime Active: The runtime is now ready to execute tasks and emit events

Error Handling

If initialization fails, run() will:
  1. Throw the error
  2. Automatically dispose all already-initialized resources
  3. Unhook process-level safety nets
try {
  const runtime = await run(app);
} catch (error) {
  console.error("Failed to start:", error);
  // Resources already cleaned up automatically
}

Build docs developers (and LLMs) love