The inject() function is the modern way to request dependencies in Angular, usable anywhere a valid injection context exists, not just constructors. This lesson covers how it works and where it shines.
What Is inject()?
inject() is a function you call to retrieve a dependency from Angular's current injector, functionally equivalent to constructor injection but usable in more places: class field initializers, functional route guards, functional interceptors, and factory provider functions.
Because inject() is called as a plain function rather than declared as a constructor parameter, it also composes more naturally with newer APIs like input() and output(), which are also just plain functions used as class field initializers.
import { Component, inject } from '@angular/core';
import { UserService } from './user.service';
@Component({ selector: 'app-profile', standalone: true, template: '{{ name }}' })
export class ProfileComponent {
private userService = inject(UserService);
name = this.userService.getCurrentUserName();
}
inject(UserService) retrieves the same singleton instance you would get from constructor injection, but as a plain function call.
inject(Token) throws if no provider is found, unless you pass { optional: true }.
inject() works with classes, InjectionTokens, and other built-in tokens like Router or ActivatedRoute.
Functional guards, resolvers, and interceptors rely on inject() since they have no constructor at all.
inject() must be called within a valid injection context, generally during class construction or inside specific Angular-provided callback functions.
inject() Cheatsheet
Where inject() is commonly used across the framework.
Context
Example
Component field
private http = inject(HttpClient);
Service field
private router = inject(Router);
Optional dependency
inject(LoggerService, { optional: true })
Functional route guard
inject(AuthService) inside CanActivateFn
Functional interceptor
inject(AuthService) inside HttpInterceptorFn
Factory provider
useFactory: () => inject(Config).apiUrl
inject() vs Constructor Injection
Both approaches ask Angular's injector for the same dependency and produce identical results at runtime; the difference is purely syntactic and about where they can be used.
// constructor injection
export class ProfileComponent {
constructor(private userService: UserService) {}
}
// inject() function
export class ProfileComponent {
private userService = inject(UserService);
}
Both give this.userService the exact same singleton UserService instance.
inject() in Functional Route Guards
Modern Angular favors functional guards (plain functions) over class-based guards. Since a function has no constructor, inject() is the only way to access dependencies inside one.
inject() also simplifies inheritance: a base class can inject its own dependencies without forcing every subclass to repeat and forward constructor parameters.
export class BaseFormComponent {
protected fb = inject(FormBuilder);
}
export class SignupFormComponent extends BaseFormComponent {
// no need to redeclare or forward fb in a constructor
form = this.fb.group({ email: [''] });
}
Common Mistakes
Calling inject() outside of a valid injection context, like inside a setTimeout callback or after component construction.
Mixing inject() and constructor injection for the same dependency in the same class inconsistently.
Assuming inject() behaves differently from constructor injection; they resolve dependencies identically.
Key Takeaways
inject() retrieves a dependency from Angular's injector as a plain function call.
It behaves identically to constructor injection but works in more places: fields, functional guards, interceptors, and factories.
It must be called within a valid injection context, most commonly during class field initialization.
It simplifies base classes and functional APIs that have no constructor to inject through.
Pro Tip
Favor inject() over constructor injection in new standalone components and services; it keeps dependencies declared as regular class fields, which reads more consistently alongside input(), output(), and signal-based state.
You now understand the inject() function. Next, learn about Singleton Services and how Angular ensures a service has exactly one shared instance.