Skip to content

Modules and Providers ​

Modules and providers are the core building blocks of a bunito application.

Providers ​

A provider is a value the container can resolve. Most providers are classes:

ts
import { Logger, Provider } from '@bunito/bunito';

@Provider({
  injects: [Logger],
})
class UsersService {
  constructor(private readonly logger: Logger) {}
}

The injects array defines constructor dependencies in order. This keeps runtime behavior explicit and friendly to TypeScript and Bun.

When dependency names are more useful than position, use object-based injections:

ts
@Provider({
  injects: {
    logger: Logger,
  },
})
class UsersService {
  private readonly logger: Logger;

  constructor(options: { logger: Logger }) {
    this.logger = options.logger;
  }
}

Modules ​

A module groups providers and imports other modules:

ts
import { LoggerModule, Module } from '@bunito/bunito';

@Module({
  imports: [LoggerModule],
  providers: [UsersService],
})
class AppModule {}

Modules are also how feature packages plug into an app. For example, HTTP apps add HTTPModule, and message-driven apps add BrokerModule plus an adapter module.

Export providers when another module should be able to inject them:

ts
@Module({
  providers: [UsersService],
  exports: [UsersService],
})
class UsersModule {}

Resolving Providers Manually ​

For scripts and small apps, you can create an app from module options and resolve providers directly:

ts
import { App, LoggerModule } from '@bunito/bunito';

const app = await App.create({
  imports: [LoggerModule],
  providers: [UsersService],
});

const usersService = await app.resolve(UsersService);

await app.start();
await app.shutdown();

This pattern is useful for workers, scripts, and tests.

Testing Modules ​

Tests can compose modules the same way application code does. Use App.start() or App.create() with inline module options, then resolve the provider under test:

ts
import { App } from '@bunito/bunito';

const app = await App.start({
  providers: [UsersService],
});

const users = await app.resolve(UsersService);

expect(users.findAll()).toEqual([]);

await app.shutdown();

Feature packages also provide test modules on the shared Test context. See Testing for Test.ConfigModule, Test.LoggerModule, Test.BunServerModule, and Test.BrokerModule.

Lifecycle Hooks ​

Providers can define lifecycle hooks:

ts
import { OnAppStart, OnDestroy, OnInit, Provider } from '@bunito/bunito';

@Provider()
class Worker {
  @OnInit()
  onInit(): void {}

  @OnAppStart()
  onAppStart(): void {}

  @OnDestroy()
  onDestroy(): void {}
}

Use them for setup, app-start actions, and teardown. Keep normal application logic in regular methods, and keep hooks idempotent enough that failures are easy to diagnose.

Where To Go Next ​