NewNode Dependency Injection v4 is now available.Ver en npm ->

Node.js DI Container

Dependency Injection for TypeScript without decorators or reflect metadata

Solve real backend wiring pain: autowire services, validate dependencies, compile your container, and keep domain code clean while teams scale.

No decoratorsNo reflect-metadataContainer validationCompiled autowiring

Autowire built for TypeScript with interface-aware resolution patterns.

Compile-time container checks before runtime surprises.

CLI + compiler passes for large project workflows.

The 30-second test

If this feels obvious, the container is doing its job

Plain classes in your domain. Strong guarantees in your container pipeline.

class UserService {
  constructor(
    private readonly repository: UserRepository,
    private readonly logger: Logger
  ) {}
}
const userService = await container.get(UserService)

What you get immediately

  • OKDependencies validated
  • OKInterfaces resolved
  • OKNo decorators
  • OKNo runtime reflection

Get started in 2 minutes

Install, wire, validate, compile.

Your classes stay plain TypeScript while the container handles wiring guarantees.

npm install node-dependency-injection
import { ContainerBuilder } from 'node-dependency-injection'
import Mailer from './services/Mailer'
import ExampleService from './services/ExampleService'

const container = new ContainerBuilder()

container.register('service.example', ExampleService)
container.register('service.mailer', Mailer).addArgument('service.example')

await container.compile()

const mailer = container.get('service.mailer')

Why this approach

Low coupling is not a side effect. It is the feature.

When dependency metadata leaks into domain classes, architecture becomes tied to a specific framework model. External wiring keeps your core portable and easier to evolve.

Domain classes stay plain TypeScript, with no framework decorators.
Container rules are explicit and reviewable in dedicated config/bootstrap files.
You can switch infrastructure without rewriting application behavior.

Feature highlights

Built for architecture-first teams

A DI container for backend products where boundaries and maintainability matter more than syntactic shortcuts.

External wiring, your format

Compose services in YAML, JSON, JS, or with a bootstrap pipeline depending on team preferences.

Autowire when it helps

Use reflection-driven autowire in integration layers while keeping business modules explicit.

Keyed and conditional services

Support runtime and environment-specific implementations without pushing decisions into domain classes.

Compiler passes

Hook advanced build-time transformations to enforce consistency at container compile stage.

Comparison

Why teams choose node-dependency-injection

When evaluating Awilix, tsyringe, and Inversify, this is where the differences show up in real projects.

Criterionnode-dependency-injectionInversifyJStsyringeAwilix
Requires decoratorsNoYesYesNo
Requires reflect-metadataNoYesYesNo
Container compilationYesNoNoNo
Container validationYesPartialPartialPartial
CLIYesNoNoNo
Compiler passesYesNoNoNo

Code snippet

Clean class, explicit wiring

Application behavior remains readable on its own. Composition details stay in wiring files where they can evolve safely.

// Domain stays clean
export class CreateInvoiceUseCase {
  constructor(private readonly gateway: InvoiceGateway) {}

  execute(input: CreateInvoiceInput) {
    return this.gateway.create(input);
  }
}
# Wiring stays outside domain (YAML, JSON, or JS bootstrap)
services:
  App\UseCase\CreateInvoiceUseCase:
    arguments:
      - '@App\Infra\StripeInvoiceGateway'

Prefer architecture longevity over container magic

If your team wants a DI model that keeps business code decoupled from tooling concerns, start with the docs and ship incrementally.