Skip to content

OneBun FrameworkA complete, batteries-included TypeScript backend framework for Bun.js

One framework. One runtime. Everything you need for production backend services.

OneBun Framework

A complete, batteries-included TypeScript backend framework for Bun.js.

OneBun brings NestJS-style architecture — modules, dependency injection, decorators — to the Bun.js runtime, with a full ecosystem of built-in packages: WebSocket (+ Socket.IO + typed client), microservices with single-image deployment, database integration (Drizzle ORM), message queues (Redis, NATS, JetStream), caching, Prometheus metrics, OpenTelemetry tracing, ArkType validation with auto-generated OpenAPI documentation, and typed inter-service HTTP clients.

One framework. One runtime. Everything you need for production backend services.

Quick Reference ​

AspectDetails
RuntimeBun.js (not Node.js compatible)
LanguageTypeScript (strict mode, no any)
ArchitectureNestJS-inspired with Effect.ts for side effects
PhilosophyOne default solution per problem
API StylePromise-based for client code, Effect.js internally

Core Concepts ​

Application Structure ​

my-app/
├── src/
│   ├── index.ts              # Entry point - creates OneBunApplication
│   ├── app.module.ts         # Root module
│   ├── config.ts             # Environment schema
│   ├── users/
│   │   ├── users.module.ts   # Feature module
│   │   ├── users.controller.ts
│   │   ├── users.service.ts
│   │   └── entities/
│   │       └── user.entity.ts
│   └── posts/
│       └── ...
├── package.json
└── tsconfig.json

Decorator System ​

DecoratorPurposeExample
@Module()Define module with imports, controllers, providers@Module({ controllers: [UserController] })
@Controller(path)Define HTTP controller@Controller('/users')
@Service()Mark class as injectable service@Service()
@Get(), @Post(), etc.Define HTTP endpoints@Get('/:id')
@Body(), @Param(), @Query()Parameter injection@Param('id') id: string
@Inject()Explicit DI (edge cases only)@Inject(AbstractService)
@WebSocketGateway()Define WebSocket gateway@WebSocketGateway({ path: '/ws' })
@OnMessage(), @OnConnect(), etc.WebSocket event handlers@OnMessage('chat:*')

Base Classes ​

ClassPurposeInherit When
BaseControllerHTTP controller functionalityCreating any controller
BaseServiceService with logger and configCreating any service
BaseWebSocketGatewayWebSocket gateway with rooms and emitCreating WebSocket gateway

Minimal Working Example ​

typescript
import {
  BaseController,
  BaseService,
  Controller,
  Env,
  Get,
  Module,
  OneBunApplication,
  Post,
  Body,
  Service,
} from '@onebun/core';

// ============================================================================
// 1. Environment Schema (src/config.ts)
// ============================================================================
const envSchema = {
  server: {
    port: Env.number({ default: 3000 }),
    host: Env.string({ default: '0.0.0.0' }),
  },
};

// ============================================================================
// 2. Service Layer (src/counter.service.ts)
// ============================================================================
@Service()
class CounterService extends BaseService {
  private value = 0;

  getValue(): number {
    this.logger.debug('Getting counter value', { value: this.value });
    return this.value;
  }

  increment(amount = 1): number {
    this.value += amount;
    return this.value;
  }
}

// ============================================================================
// 3. Controller Layer (src/counter.controller.ts)
// ============================================================================
@Controller('/api/counter')
class CounterController extends BaseController {
  constructor(private counterService: CounterService) {
    super();
  }

  @Get('/')
  async getValue(): Promise<Response> {
    const value = this.counterService.getValue();
    return this.success({ value });
  }

  @Post('/increment')
  async increment(@Body() body?: { amount?: number }): Promise<Response> {
    const newValue = this.counterService.increment(body?.amount);
    return this.success({ value: newValue });
  }
}

// ============================================================================
// 4. Module Definition (src/app.module.ts)
// ============================================================================
@Module({
  controllers: [CounterController],
  providers: [CounterService],
})
class AppModule {}

// ============================================================================
// 5. Application Entry Point (src/index.ts)
// ============================================================================
const app = new OneBunApplication(AppModule, {
  port: 3000,
  envSchema,
  metrics: { enabled: true },
  tracing: { enabled: true },
});

app.start();

Key Patterns ​

Response Format ​

Always use standardized responses:

typescript
// Success
return this.success(data);           // { success: true, result: data }

// Error
return this.error('message', 400);   // { success: false, code: 400, message: 'message' }

Dependency Injection ​

Dependencies are auto-detected from constructor:

typescript
@Controller('/users')
export class UserController extends BaseController {
  // CounterService is automatically injected
  constructor(private counterService: CounterService) {
    super();
  }
}

Validation with ArkType ​

typescript
import { type } from 'arktype';

const createUserSchema = type({
  name: 'string',
  email: 'string.email',
  age: 'number > 0',
});

@Post('/')
async createUser(@Body(createUserSchema) user: typeof createUserSchema.infer) {
  // user is validated and typed
}

Commands ​

bash
# Development
bun run dev           # Start with watch mode
bun run dev:once      # Start once

# Testing
bun test              # Run all tests

# Type checking
bunx tsc --noEmit     # Check TypeScript errors

# Linting
bun lint              # Check lint errors

Package Dependencies ​

json
{
  "dependencies": {
    "@onebun/core": "^0.2.6",
    "@onebun/logger": "^0.2.0",
    "@onebun/envs": "^0.2.0",
    "@onebun/requests": "^0.2.0",
    "@onebun/metrics": "^0.2.0",
    "@onebun/trace": "^0.2.0",
    "@onebun/cache": "^0.2.2",
    "@onebun/drizzle": "^0.2.1",
    "effect": "^3.x",
    "arktype": "^2.x"
  }
}

Released under the LGPL-3.0 License.