| name | bun-server-best-practices |
| description | MUST be used for Bun Server tasks. Covers project setup, DI, controllers, modules, middleware, validation, error handling, official modules, Platform Adapter (v3.0+), and AI modules (v2.0+). Load for any Bun Server, @dangao/bun-server, decorator-driven DI, or framework-related work. ALWAYS follow the workflow steps below. |
Bun Server Best Practices Workflow
Use this skill as an instruction set. Follow the workflow in order unless the user explicitly asks for a different order.
Core Principles
- Decorator-driven architecture: Use decorators (
@Injectable, @Controller, @Module) as the primary configuration mechanism.
- Explicit dependency injection: Keep DI contracts clear with Symbol+Interface pattern when needed.
- Modular organization: Split by feature domain, one module per business boundary.
- Convention over configuration: Follow established patterns for project structure and module setup.
- Type safety: Leverage TypeScript decorators and typed contracts throughout.
- Platform portability: Use
IWebSocket<T> and IServerHandle (not Bun-specific types) to keep code runnable on both Bun and Node.js 22+.
1) Confirm architecture before coding (required)
- Default stack: Bun Runtime +
@dangao/bun-server + TypeScript with decorators enabled.
- Current stable reference version:
@dangao/bun-server v3.0.5 (update docs/examples based on this line unless user pins another version).
- Verify
tsconfig.json has experimentalDecorators: true and emitDecoratorMetadata: true.
1.1 Must-read core references (required)
Before implementing any Bun Server task, make sure to read and apply these core references:
- quickstart - Project setup, minimal/modular application, common imports
- dependency-injection - @Injectable, @Inject, scopes, Symbol+Interface pattern
- module-system - @Module, imports/exports, forRoot pattern, modular architecture
- platform - v3 required: Platform Adapter,
IWebSocket<T>, IServerHandle, Bun vs Node.js support matrix
Keep these references in active working context for the entire task.
1.2 Plan module boundaries before coding (required)
Create a brief module map before implementation for any non-trivial feature:
- Define each module's responsibility in one sentence.
- Identify which modules need
forRoot() configuration (must be called before module definitions).
- Define provider/export contracts between modules.
- Follow the recommended project structure:
src/
├── main.ts # Entry point
├── app.module.ts # Root module
├── common/ # Shared utilities
│ ├── middleware/
│ ├── filters/
│ └── guards/
├── users/ # Feature module
│ ├── user.module.ts
│ ├── user.controller.ts
│ ├── user.service.ts
│ └── dto/
└── orders/ # Feature module
├── order.module.ts
└── ...
2) Apply core framework foundations (required)
These are essential foundations. Apply all of them in every Bun Server task using the core references already loaded in section 1.1.
Dependency Injection
- Must-read reference from
1.1: dependency-injection
- Mark all services with
@Injectable().
- Use constructor injection as the primary injection method.
- Use Symbol+Interface pattern for abstract service contracts.
- Choose appropriate scopes: Singleton (default), Transient, or Request-scoped.
Controllers and Routing
- Must-read reference: controller-routing
- Use
@Controller with route prefix for grouping endpoints.
- Use HTTP method decorators (
@GET, @POST, @PUT, @DELETE) for route definitions.
- Use parameter decorators (
@Body, @Query, @Param, @Header, @Ctx) for request data binding.
- Return objects directly for auto JSON serialization; use
ResponseBuilder for special responses.
Middleware and Interceptors
- Must-read reference: middleware
- Use built-in middleware for common concerns (CORS, logging, rate limiting, static files).
- Create custom middleware for cross-cutting concerns.
- Use interceptors for pre/post request processing (logging, transformation, caching).
- Follow the execution order: Global -> Controller -> Method for both middleware and interceptors.
Guards
- Must-read reference: guards
- Implement
CanActivate for access control (authentication, authorization, feature flags).
- Use
@UseGuards() at controller or method level.
- Use built-in
AuthGuard, OptionalAuthGuard, RolesGuard + @Roles() when possible.
- Use
Reflector + metadata for dynamic guard logic.
- Prefer throwing
UnauthorizedException / ForbiddenException over returning false.
Validation
- Must-read reference: validation
- Define DTOs with validation decorators (
@IsString, @IsEmail, @Min, etc.).
- Use
@Validate(DtoClass) on controller methods.
- Use
ValidateNested + @Type() for nested objects.
- Use
PartialType() for update DTOs.
Error Handling
- Must-read reference: error-handling
- Use built-in exceptions (
NotFoundException, BadRequestException, etc.).
- Create custom exceptions extending
HttpException for domain-specific errors.
- Register global exception filters for consistent error responses.
- Async errors in handlers are automatically caught.
3) Load official modules only when requirements call for them
Do not add these by default. Load the matching reference only when the requirement exists.
Configuration
- Type-safe config, env vars, config files (.json/.jsonc/.json5), dynamic refresh, Nacos config center -> config
- Async config loading from remote sources -> async-module
Authentication and Authorization
- JWT, OAuth2, guards, roles, access control -> security
- Session management, session stores, user state -> session
Data and Storage
- Database connections, ORM, entities, repositories, transactions -> database
- Async DB config from ConfigService or secrets -> async-module
- Caching with @Cacheable, cache eviction, Redis cache -> cache
Async Processing
- Job queues, background tasks, @Cron scheduled tasks -> queue
- Event-driven architecture, EventModule, @OnEvent (v1.9.0+: auto-scans listeners at
app.listen(), no manual initializeListeners needed) -> events
Communication
- WebSocket gateways, real-time features -> websocket
Documentation and Observability
- API documentation, OpenAPI, Swagger UI -> swagger
- Health checks, Prometheus metrics, monitoring -> health-metrics
- Logging, log levels, structured logging -> logger
- Embedded monitoring Web UI (routes, health, system info) -> dashboard
- HTTP request recording, debug UI, JSONL export -> debug
Testing and Development Tools
- Integration tests, module isolation, provider mocking, HTTP test client -> testing
- Type-safe API client generation from route manifest -> client
Lifecycle Management
- Startup/shutdown hooks,
OnModuleInit, OnApplicationBootstrap, OnApplicationShutdown -> lifecycle
Deployment and Scaling
- Multi-process clustering, CPU core utilization, worker crash recovery -> cluster
- Platform adapter, Node.js 22+ support, runtime detection -> platform
AI Application Modules (v2.0+)
- Unified LLM access, Tool Calling, streaming responses -> ai
- Includes
AiModule, ConversationModule, PromptModule, EmbeddingModule, VectorStoreModule, RagModule, McpModule, AiGuardModule
4) Microservice extensions (only when building distributed systems)
Only load when the project explicitly requires microservice architecture:
- Service discovery, config center, load balancing, circuit breaker, distributed tracing -> microservice
5) Final self-check before finishing
- Core behavior works and matches requirements.
- All must-read references from
1.1 were read and applied.
tsconfig.json has experimentalDecorators and emitDecoratorMetadata enabled.
- DI contracts are explicit:
@Injectable() on all services, proper @Inject() where needed.
- Module boundaries are clear: providers registered, exports declared for cross-module usage.
forRoot() calls happen before module definitions for all configurable modules.
- Controllers use proper parameter decorators and return typed responses.
- Validation DTOs are defined and applied to controller methods.
- Error handling follows framework patterns (HttpException, exception filters).
- Optional modules are used only when requirements demand them.
- Event listener classes using
@OnEvent are registered in a module's providers (required for auto-scan in v1.9.0+).
- [v3] WebSocket handlers use
IWebSocket<T> (from @dangao/bun-server), NOT ServerWebSocket<T> from bun.
- [v3]
app.getServer() returns IServerHandle | undefined, NOT Bun.Server | undefined.
- [v3] If targeting Node.js, verify
idleTimeout and reusePort are not relied on (Bun-only; silently ignored on Node.js).
- If something is not working, check troubleshooting.