Overview
bunito is designed around a small idea: application code should be organized as plain TypeScript classes, and framework behavior should be added through explicit modules and decorators.
The result is a framework that feels close to Bun and TypeScript. You define providers, compose them into modules, and let the container resolve dependencies and call lifecycle hooks.
Philosophy
bunito favors:
- small packages with clear responsibilities
- explicit dependency lists instead of hidden reflection
- decorators for framework metadata, not business logic
- Bun-native runtime behavior
- examples that show real application structure
The main package, @bunito/bunito, gives you the application and container APIs. Feature packages add focused capabilities. For example, @bunito/http adds routes, HTTP injections, middleware, and exceptions; @bunito/broker adds message handlers and adapters; @bunito/config plus @bunito/logger handle common application concerns.
Modules
Modules group providers and features.
import { Module } from '@bunito/bunito';
@Module({
imports: [],
providers: [],
})
class AppModule {}A module can import other modules, register providers, expose controllers through feature packages, and configure extensions.
Modules can also export providers for other modules:
@Module({
providers: [UsersService],
exports: [UsersService],
})
class UsersModule {}Providers
Providers are classes, factories, or values registered in the container. The most common form is a class provider:
import { Logger, Provider } from '@bunito/bunito';
@Provider({
injects: [Logger],
})
class UsersService {
constructor(private readonly logger: Logger) {}
}The injects array is deliberately explicit. It tells bunito which dependencies should be passed to the constructor or factory.
Use object-based injects when names are clearer than constructor order:
@Provider({
injects: {
logger: Logger,
},
})
class UsersService {
private readonly logger: Logger;
constructor(options: { logger: Logger }) {
this.logger = options.logger;
}
}Provider Scopes
Providers can live in different scopes:
singleton: one instance for the whole appmodule: one instance for a module contextrequest: one instance for a request contexttransient: a new instance whenever it is resolved
Most application services can stay in the default scope. Request scope is backed by the container request context. HTTP requests, broker messages, and Bun server websocket events enter that context automatically, so request-scoped providers and log correlation stay isolated per request.
Lifecycle
Providers can react to container and application events:
import { OnAppStart, OnDestroy, OnInit, Provider } from '@bunito/bunito';
@Provider()
class Worker {
@OnInit()
onInit(): void {}
@OnAppStart()
onAppStart(): void {}
@OnDestroy()
onDestroy(): void {}
}Use lifecycle hooks for setup and teardown that belongs to a provider. Keep request handling and business behavior in normal methods.
Feature Packages
The framework is split into packages so applications can stay small:
@bunito/bunito: the convenience entrypoint for app, container, config, logger, and common APIs@bunito/app: application bootstrap, lifecycle coordination, and app hooks@bunito/container: dependency injection, modules, providers, scopes, request contexts, and indexed extensions@bunito/config: typed config factories, environment parsing, runtime flags, and secret lookup@bunito/logger: injectable loggers, trace helpers, and JSON/pretty transports@bunito/common: shared exceptions, predicates, type helpers, and utilities@bunito/http: controllers, routing decorators, middleware, CORS, validation, response handling, and HTTP exceptions@bunito/broker: message handlers, broker injections, local/NATS adapters, and request/reply APIs@bunito/bun: Bun-specific server and secrets integrations@bunito/testing: shared test context factories, mock helpers, spies, and testing exceptions for package tests
Examples
Runnable examples live in separate workspaces under examples/:
examples/basics: one standard appexamples/http: HTTP apps discovered fromapps/*/src/main.tsexamples/microservices: broker apps that call each other through messagesexamples/monorepo: several apps plus a shared library
Multi-app examples use app-local .env files for ports and broker settings.
Continue with Modules and Providers or jump straight into Testing, HTTP, or Broker.
