A NestJS-inspired dependency injection and module system for ElysiaJS.
Installation • Quick Start • Features • Documentation • API Reference
ElysiaJS-DI brings the power of NestJS-style architecture to ElysiaJS applications. It provides:
- 🏗️ Module System - Organize your application into cohesive modules
- 💉 Dependency Injection - Powered by TSyringe for robust DI
- 🎯 Decorators - Familiar decorators like
@Controller,@Get,@Post - ♻️ Lifecycle Hooks -
OnModuleInit,OnApplicationShutdown, and more - ✅ Validation - Built-in Zod schema validation support
- 📝 NestJS-style Logging - Beautiful, structured console output
- 📚 OpenAPI/Swagger - Automatic API documentation generation
- 📊 OpenTelemetry - Distributed tracing and observability
This package is designed for Bun runtime. Install it using:
bun add @igorcesarcode/elysiajs-di reflect-metadata tsyringeNote: While this package may work with Node.js, it's optimized for Bun and requires Bun >= 1.3.0.
Add the following to your tsconfig.json:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}import { Elysia } from "elysia";
import {
Module,
Controller,
Get,
Post,
Singleton,
ModuleFactory,
ApplicationLogger,
} from "@igorcesarcode/elysiajs-di";
import { z } from "zod";
// 1. Create a Service
@Singleton()
class UserService {
private readonly logger = new ApplicationLogger(UserService.name);
private users = [{ id: 1, name: "John Doe" }];
findAll() {
this.logger.log("Fetching all users");
return this.users;
}
}
// 2. Create a Controller
@Controller("/users")
class UserController {
constructor(private userService: UserService) {}
@Get()
getAllUsers() {
return this.userService.findAll();
}
@Post("/", {
body: z.object({
name: z.string().min(2),
}),
})
createUser({ body }) {
return { id: Date.now(), ...body };
}
}
// 3. Create a Module
@Module({
controllers: [UserController],
providers: [UserService],
})
class UserModule {}
// 4. Create Root Module
@Module({
imports: [UserModule],
})
class AppModule {}
// 5. Bootstrap the Application
const app = new Elysia();
const factory = new ModuleFactory();
await factory.bootstrap(AppModule, app);
app.listen(3000, () => {
console.log("🚀 Server running at http://localhost:3000");
});Organize your application into feature modules:
@Module({
imports: [SharedModule], // Import other modules
controllers: [UserController], // HTTP Controllers
providers: [UserService], // Services/Providers
exports: [UserService], // Export for other modules
})
class UserModule {}Use @Singleton() for shared instances or @Injectable() for transient instances:
@Singleton()
class DatabaseService {
// Same instance across the application
}
@Injectable()
class RequestService {
// New instance for each injection
}Full suite of HTTP method decorators:
@Controller('/api/users')
class UserController {
@Get() // GET /api/users
@Get('/:id') // GET /api/users/:id
@Post() // POST /api/users
@Put('/:id') // PUT /api/users/:id
@Patch('/:id') // PATCH /api/users/:id
@Delete('/:id') // DELETE /api/users/:id
}Built-in support for Zod schema validation:
@Post('/', {
body: z.object({
name: z.string().min(2),
email: z.string().email()
}),
params: z.object({
id: z.coerce.number()
})
})
createUser({ body, params }) {
// body and params are validated and typed!
}Hook into application lifecycle events:
@Singleton()
class DatabaseService implements OnModuleInit, OnApplicationShutdown {
async onModuleInit() {
// Connect to database
}
async onApplicationShutdown(signal?: string) {
// Close connections
}
}NestJS-style logging with colors:
@Singleton()
class UserService {
private readonly logger = new ApplicationLogger(UserService.name);
findAll() {
this.logger.log("Fetching users"); // Green
this.logger.warn("Cache miss"); // Yellow
this.logger.error("Database error"); // Red
this.logger.debug("Query executed"); // Magenta
}
}Output:
[Elysia] 12345 - 12/09/2025 - 05:30 PM LOG [UserService] Fetching users +0ms
[Elysia] 12345 - 12/09/2025 - 05:30 PM WARN [UserService] Cache miss +1ms
[Elysia] 12345 - 12/09/2025 - 05:30 PM ERROR [UserService] Database error +0ms
Generate automatic API documentation:
bun add @elysiajs/openapiimport { registerOpenAPI, SecuritySchemes } from "@igorcesarcode/elysiajs-di";
// After bootstrap
await registerOpenAPI(app, {
path: "/swagger",
documentation: {
info: {
title: "My API",
version: "1.0.0",
},
tags: [{ name: "Users", description: "User endpoints" }],
components: {
securitySchemes: {
bearerAuth: SecuritySchemes.bearerAuth,
},
},
},
});
// Add OpenAPI details to routes
@Get("/", {
detail: {
tags: ["Users"],
summary: "Get all users",
description: "Returns a list of all users",
},
})
getAllUsers() {
return this.userService.findAll();
}Add distributed tracing:
bun add @elysiajs/opentelemetryimport { registerOpenTelemetry } from "@igorcesarcode/elysiajs-di";
// Register BEFORE bootstrap
await registerOpenTelemetry(app, {
serviceName: "my-api",
});
// Then bootstrap
await factory.bootstrap(AppModule, app);For detailed documentation, see the docs folder:
- Getting Started
- Modules
- Controllers
- Providers
- Lifecycle Hooks
- Validation
- Logging
- OpenAPI Integration
- OpenTelemetry Integration
| Decorator | Description |
|---|---|
@Module(metadata) |
Defines a module with imports, controllers, providers, exports |
@Controller(path) |
Defines an HTTP controller with a base path |
@Get(path?, options?) |
HTTP GET route |
@Post(path?, options?) |
HTTP POST route |
@Put(path?, options?) |
HTTP PUT route |
@Delete(path?, options?) |
HTTP DELETE route |
@Patch(path?, options?) |
HTTP PATCH route |
@Singleton() |
Marks class as singleton (shared instance) |
@Injectable() |
Marks class as injectable (new instance each time) |
| Interface | Method | When Called |
|---|---|---|
OnModuleInit |
onModuleInit() |
After module dependencies are resolved |
OnApplicationBootstrap |
onApplicationBootstrap() |
After all modules initialized |
OnModuleDestroy |
onModuleDestroy() |
When shutdown signal received |
BeforeApplicationShutdown |
beforeApplicationShutdown(signal) |
Before listeners stop |
OnApplicationShutdown |
onApplicationShutdown(signal) |
After listeners stopped |
| Class | Description |
|---|---|
ModuleFactory |
Bootstraps the application and manages modules |
ApplicationLogger |
NestJS-style logger for use in services |
| Function | Description |
|---|---|
registerOpenAPI |
Register OpenAPI/Swagger documentation |
registerOpenTelemetry |
Register OpenTelemetry tracing |
registerAxiomTelemetry |
Register OpenTelemetry with Axiom backend |
getCurrentSpan |
Get current OpenTelemetry span for custom attrs |
createOpenAPIDetail |
Helper to create OpenAPI route details |
SecuritySchemes |
Pre-configured security schemes (Bearer, API Key) |
- Bun >= 1.3
- Zod >= 3.24
- TypeScript >= 5.0
- ElysiaJS >= 1.4
MIT © 2025
Contributions are welcome! Please read our Contributing Guide for details.