Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Angular dependency injection (DI) lets a class receive services and other dependencies from outside instead of constructing them itself. The provider you choose determines where Angular can supply a value and whether consumers share an instance or receive an isolated one. For new applications, build with standalone components; understand NgModules to maintain existing applications, not as a reason to create more modules.

How Angular dependency injection supports modular design

A component should focus on its own behavior rather than decide how to create every collaborator it needs. With DI, the component requests a dependency and Angular supplies it from a configured provider. This reduces direct construction between classes, makes implementations easier to replace, and lets tests use substitutes such as fakes or mocks.

Angular can provide some dependencies automatically, while others need explicit provider configuration. A class is a common DI token; use an InjectionToken when the dependency is a non-class value, such as configuration, or when callers should depend on an abstraction rather than a particular implementation. Angular’s dependency injection guide and DI essentials explain the core concepts.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Request a dependency

In a component or service, use inject() to request a token. Constructor injection is also appropriate, particularly in codebases that already use it. In either case, the class asks for the dependency; it does not choose how the dependency is constructed.

import { Component, inject } from '@angular/core';
import { LoggerService } from './logger.service';

@Component({
  selector: 'app-dashboard',
  template: '<p>Dashboard</p>',
})
export class DashboardComponent {
  private readonly logger = inject(LoggerService);
}

This example assumes LoggerService is provided somewhere in the injector hierarchy. If Angular cannot find a provider for the requested token, resolution fails; provide the dependency at an appropriate scope or configure automatic provision where that fits the service.

Choose provider scope based on sharing and isolation

Angular looks for a dependency starting at the requesting component’s injector and moving upward until it finds a provider. As the official provider guide puts it: “When a component requests a dependency, Angular starts with that component’s injector and walks up the tree until it finds a provider for that dependency.” This hierarchy is why provider location is a design decision: it controls availability and instance sharing.

Provider location Use it for Sharing and isolation
Application-level providers Services and configuration used broadly across the application. Consumers that resolve the provider through the application injector can share its provided instance.
Route-level providers Dependencies or configuration needed by a feature or route. Limits availability to the route’s injector context; useful for feature-specific provisioning.
Component-level providers State or behavior that belongs to a component and its descendants. A provider can create an instance scoped to that component tree rather than sharing the broader instance.

Application scope: share broadly

Put a dependency in application-level providers when it represents shared application behavior or global configuration. This avoids configuring the same service separately in unrelated parts of the app. Do not choose this scope automatically for state that should belong to an individual feature or component tree.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Route scope: keep feature dependencies local

Route providers are useful when a dependency or configuration belongs to a particular feature. They make the dependency available in that route’s context without treating it as application-wide. Use this scope when the feature boundary is clearer than a single component boundary.

Component scope: isolate local state

Configure a provider on a component when that component and its descendants should use a locally scoped dependency. This is useful for state that should not be shared with other instances of the same component elsewhere. A locally configured provider can create an isolated instance; consumers below it resolve through that local injector before searching higher levels.

Provider placement should follow ownership and sharing needs, not a blanket rule that every service belongs at the root. Lifecycle and bundling effects are not identical across provider strategies, so do not infer either solely from the fact that a service is injectable. Consult Angular’s provider documentation for the specific provider form and scope you use.

Use standalone components for new code

Angular recommends standalone components for new code. A standalone component declares its template dependencies through its imports, making the dependencies used by that template explicit at the component level. This provides a modular structure without requiring an NgModule for every feature.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For example, a standalone component can import the directives, pipes, or other components its template uses. Keep those imports aligned with the template’s actual dependencies so the component’s needs are visible where it is defined. See Angular’s NgModules guide for the current distinction and guidance.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Understand NgModules in existing applications

NgModules remain relevant when you read or maintain applications built around them. An NgModule groups declarations and imports, can export declarations for other modules, and can configure providers. In that model, the module’s metadata helps determine which declarations are available and where dependencies are provided.

Do not treat modular design as a mandate to create many NgModules. In new code, standalone components are Angular’s recommended default; in an existing NgModule-based project, work with its established structure unless you have a reason to migrate. Mixing the two approaches may be appropriate during a transition, but keep dependency ownership and provider scope clear.

Migrate an existing project incrementally

Angular documents standalone migration as a three-step schematic workflow. Start with a project that builds, check its Angular version, and apply each stage incrementally rather than treating migration as a single all-at-once rewrite.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Convert components, directives, and pipes to standalone.
  2. Remove NgModule classes that are no longer necessary.
  3. Switch the application to standalone bootstrapping.

The standalone migration guide warns that manual fixes may be needed. Resolve build or migration issues at each stage before proceeding. Version context matters: Angular’s components guide states that before Angular 19, standalone defaulted to false, so older projects may contain explicit metadata or assumptions that differ from current defaults.

A practical decision checklist

  • Have each class request its collaborators through DI instead of constructing them directly.
  • Use a class token for a typical service and an InjectionToken for non-class values or interchangeable implementations.
  • Place broadly shared services and global configuration at application scope.
  • Use route providers for dependencies tied to a feature, and component providers when descendants should share local state isolated from other component trees.
  • Build new components as standalone; use NgModule concepts to understand and maintain existing code.
  • If migrating, verify the Angular version, begin from a buildable project, follow the documented steps in order, and account for manual fixes.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.