From monotemplate
Wire classes into the Inversify DI container correctly. Use when adding new repositories, controllers, services, or middleware to the server. Use when wiring dependencies, configuring the DI container, or understanding how classes are resolved.
How this skill is triggered — by the user, by Claude, or both
Slash command
/monotemplate:diThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
The monotemplate uses **Inversify v7** with `reflect-metadata` for decorator-based dependency injection. All DI configuration lives in `apps/server/src/di/container.ts`, which exports a singleton `container` instance.
The monotemplate uses Inversify v7 with reflect-metadata for decorator-based dependency injection. All DI configuration lives in apps/server/src/di/container.ts, which exports a singleton container instance.
Every Repository, Controller, and Service class must be decorated with @injectable(). Constructor dependencies use @inject(ClassName) parameter decorators. Import the class itself (not type-only) so the class token is available at runtime.
import { injectable, inject } from "inversify";
import { SomeRepository } from "@server/repositories/SomeRepository";
@injectable()
export class SomeController {
constructor(@inject(SomeRepository) private someRepository: SomeRepository) {}
}
container.ts| Pattern | Use case | Example |
|---|---|---|
toSelf().inSingletonScope() | Classes that auto-resolve their own deps | Repositories, Controllers |
toConstantValue(value) | External/constant values | PrismaClient, env-gated services |
to(ConcreteClass).inSingletonScope() | Abstract to concrete | Auth factories |
bind(SYMBOL).toConstantValue(value) (repeated) | Multi-bindings | Express middleware |
Follow this order in container.ts:
// Database
container.bind(PrismaClient).toConstantValue(prisma);
// Middleware (multi-binding via Symbol token)
container.bind(EXPRESS_MIDDLEWARE).toConstantValue(helmet());
container.bind(EXPRESS_MIDDLEWARE).toConstantValue(express.json());
// Auth (abstract → concrete, with simulated mode gating)
if (isSimulated()) {
container.bind(AuthContextFactory).to(SimulatedAuthContextFactory).inSingletonScope();
} else {
container.bind(AuthContextFactory).to(ClerkAuthContextFactory).inSingletonScope();
}
// Repositories
container.bind(FooRepository).toSelf().inSingletonScope();
// Controllers
container.bind(FooController).toSelf().inSingletonScope();
container.get(ClassName) — import both container and the classserver.ts: container.get(AuthContextFactory), container.getAll<T>(EXPRESS_MIDDLEWARE)container.get()import { container } from "@server/di/container";
import { UsersController } from "@server/controllers/UsersController";
const result = await container.get(UsersController).getUserById(id);
di/tokens.ts)Used for multi-bindings where multiple values share one key (e.g., EXPRESS_MIDDLEWARE).
export const TOKEN_NAME = Symbol.for("TokenName");
__dev__/ directory code is dynamically imported inside isSimulated() checks (Bun macro)__dev__/ code in production pathsif (isSimulated()) {
const { SimulatedAuthContextFactory } = await import("@server/__dev__/SimulatedAuthContextFactory");
container.bind(AuthContextFactory).to(SimulatedAuthContextFactory).inSingletonScope();
}
When a service depends on an env variable that may not be set, bind it as ServiceClass | null:
container.bind<StorageService | null>(StorageService).toConstantValue(
env.SOME_KEY ? new StorageService({ ... }) : null,
);
// Resolve with explicit type annotation:
const svc = container.get<StorageService | null>(StorageService);
experimentalDecorators: true and emitDecoratorMetadata: true must be setimport "reflect-metadata" must be the first import in the entry point (index.ts)When adding a new Repository, Controller, or Service:
@injectable() to the class@inject(Dep) to each constructor parametertype-only) for injected dependenciescontainer.ts under the appropriate sectioncontainer.get(ClassName)npx claudepluginhub firstloophq/claude-code-plugins --plugin monotemplateMaster NestJS DI container with tokens, useClass/useValue/useFactory providers, and async initialization. Helps resolve 'Cannot resolve dependencies' errors.
Generates DI container configuration for PHP 8.4 projects following DDD and Clean Architecture. Supports Symfony, Laravel, PHP-DI; creates modules, service providers, YAML configs, compiler passes, unit tests.
Covers .NET dependency injection patterns: service lifetimes, keyed services, decorator pattern, and common pitfalls. Useful when registering services or resolving lifetime issues.