Quick Start
This guide will walk you through the basic concepts of di-framework with simple examples.
To scaffold a ready-to-run app instead of pasting these snippets by hand:
bun x @di-framework/cli init my-api
cd my-api && bun install && bun run dev
See CLI for check, build, and options. The sections below cover the same concepts the scaffold uses.
1. Basic Service
The simplest way to use the framework is to mark a class with the @Container() decorator:
import { Container } from '@di-framework/core/decorators';
@Container()
export class DatabaseService {
connect(): void {
console.log('Connected to database');
}
query(sql: string) {
console.log('Executing query:', sql);
return { rows: [] };
}
}
The @Container() decorator automatically registers the service with the DI container.
2. Service with Dependencies
You can inject dependencies into your services using the @Component() decorator:
Property Injection
import { Container, Component } from '@di-framework/core/decorators';
import { DatabaseService } from './DatabaseService';
@Container()
export class UserService {
@Component(DatabaseService)
private db!: DatabaseService;
constructor() {}
getUser(id: string) {
return this.db.query(`SELECT * FROM users WHERE id = '${id}'`);
}
}
Constructor Injection
@Container()
export class UserService {
constructor(@Component(DatabaseService) private db: DatabaseService) {}
getUser(id: string) {
return this.db.query(`SELECT * FROM users WHERE id = '${id}'`);
}
}
3. Resolving Services
To use your services, resolve them from the container:
import { useContainer } from '@di-framework/core/container';
import { UserService } from './UserService';
const container = useContainer();
const userService = container.resolve<UserService>(UserService);
// All dependencies are automatically injected!
const user = userService.getUser('123');
4. Multiple Dependencies
You can inject multiple dependencies into a single service:
@Container()
export class ApplicationContext {
constructor(
@Component(DatabaseService) private db: DatabaseService,
@Component(LoggerService) private logger: LoggerService,
@Component(AuthService) private auth: AuthService,
) {}
async initialize() {
this.logger.log('Initializing application...');
await this.db.connect();
this.auth.setup();
}
}
5. How It Works
When you call container.resolve(ServiceClass):
The container creates a new instance (or returns existing singleton)
It examines the constructor parameters and their types
It recursively resolves each dependency
Dependencies are injected into the constructor or properties
The configured instance is returned
By default, all services are singletons - the same instance is reused across your application.
Complete Example
Here's a complete example showing how everything works together:
// DatabaseService.ts
import { Container } from '@di-framework/core/decorators';
@Container()
export class DatabaseService {
connect() {
console.log('Database connected');
}
query(sql: string) {
return { rows: [] };
}
}
// UserService.ts
import { Container, Component } from '@di-framework/core/decorators';
import { DatabaseService } from './DatabaseService';
@Container()
export class UserService {
@Component(DatabaseService)
private db!: DatabaseService;
getUser(id: string) {
return this.db.query(`SELECT * FROM users WHERE id = '${id}'`);
}
}
// main.ts
import { useContainer } from '@di-framework/core/container';
import { UserService } from './UserService';
const container = useContainer();
const userService = container.resolve(UserService);
const user = userService.getUser('123');
console.log(user);
Next Steps
CLI - App init/check/build and maintainer mx
Runtime type checks - Emit-time parameter guards (init wires @di-framework/tsc)
API Reference - Learn about all available APIs and options
Advanced Usage - Explore advanced patterns like transient services and factory functions
Best Practices - Learn recommended patterns and approaches
Last modified: 09 August 2026