Dependency Injection Explained
Decouple your components by injecting dependencies from the outside — enabling testability, flexibility, and clean architecture.
Dependency Injection
Dependency injection is a design pattern where a component receives its dependencies from external sources rather than creating them internally, enabling loose coupling, testability, and flexible configuration.
Explanation
Without dependency injection, a class creates its own dependencies — for example, instantiating a database connection inside a service class. This tightly couples the class to a specific implementation, making it impossible to test in isolation or swap implementations without modifying the class. Dependency injection inverts this: dependencies are "injected" from the outside, typically through constructor parameters, method parameters, or property setters. The class declares what it needs (usually via an interface), and the caller provides the concrete implementation. This enables replacing real dependencies with mocks during testing, swapping implementations (e.g., switching from MySQL to PostgreSQL), and configuring behavior through composition rather than modification. DI containers (Spring, NestJS, Angular's injector, InversifyJS) automate dependency resolution by scanning for declarations and wiring dependencies automatically. While helpful for large applications, manual DI (passing dependencies through constructors) is simpler and sufficient for many projects.
Bookuvai Implementation
Bookuvai uses dependency injection as a default architectural pattern. NestJS projects use the built-in DI container. Other Node.js projects use constructor injection with manual wiring. Every service receives its dependencies through the constructor, making unit testing straightforward and implementation swapping trivial.
Key Facts
- Components receive dependencies from external sources rather than creating them
- Enables loose coupling, testability, and implementation swapping
- Three forms: constructor injection, method injection, and property injection
- DI containers (Spring, NestJS) automate dependency resolution
- Constructor injection is the most common and recommended form
Related Terms
Frequently Asked Questions
- What is the difference between dependency injection and a service locator?
- Dependency injection pushes dependencies into a component from the outside. A service locator lets the component pull dependencies from a global registry. DI is preferred because dependencies are explicit in the constructor signature, while service locators hide dependencies.
- Do I need a DI container?
- Not always. For small to medium projects, manual constructor injection is simple and effective. DI containers add value in large applications with complex dependency graphs, where manually wiring hundreds of dependencies becomes unwieldy.
- Why is constructor injection preferred over property injection?
- Constructor injection makes dependencies explicit and required — an object cannot be created without them. Property injection allows partially constructed objects, making it unclear which dependencies are needed and enabling runtime errors from missing dependencies.