Skip to content

Dependency Injection

DomusJS is built around explicit dependency injection (DI) using tsyringe, a lightweight, TypeScript-friendly inversion of control (IoC) container.

This approach ensures:

✅ Clear separation of concerns.
✅ Easy testing (you can swap dependencies for mocks).
✅ Extensibility (replace or extend services without rewriting internals).


Dependency injection is a design pattern where:

  • Objects do not create their own dependencies.
  • Instead, dependencies are provided (injected) by an external container.

This makes your system:

  • More modular.
  • More testable.
  • Less coupled.

DomusJS configures its services, buses, handlers, and modules through the tsyringe container.

Example:

import { container } from 'tsyringe';
import { InMemoryCommandBus } from '@domusjs/infrastructure';
container.register('CommandBus', {
useClass: InMemoryCommandBus,
});

When you later resolve:

const commandBus = container.resolve('CommandBus');

You get the same registered instance, fully type-safe.


Using DI allows:

  • Isolated instances (if needed).
  • Flexible testing setups.
  • Cleaner architecture (no hidden globals or magic singletons).

Each bounded context (like auth, videos, etc.) is responsible for registering its own services in the container.

Example:

container.register<AuthService>('AuthService', {
useClass: JWTAuthService,
});

This keeps context boundaries clear and avoids leaking dependencies.


  • All core modules (auth, jobs, observability, etc.) are injectable.
  • Handlers (commands, queries, events) can receive injected services.
  • You can replace internal implementations (e.g., swap PinoLogger for your custom logger).