← Back to Articles         
What is the inject() Function in Angular?

What is the inject() Function in Angular?

Published on 30 Sep 2026     8 min read Angular
Services & Dependency Injection

1. What is the inject() Function in Angular?

What is inject()?

inject() is an Angular function used to retrieve a dependency from Angular's Dependency Injection system without declaring that dependency as a constructor parameter.

Traditional constructor injection:

constructor(private productService: ProductService) {
}

Using inject():

private productService = inject(ProductService);

Both ask Angular's DI system for a ProductService.

Constructor Injection             inject()

constructor(                      private service =
  private service:                  inject(ProductService);
    ProductService
) {}
        │                              │
        └──────────┬───────────────────┘
                   ↓
             Angular Injector
                   ↓
             ProductService

2. Why Do We Need inject()?

Constructor injection works very well, but Angular also has APIs where a constructor either doesn't exist or isn't the most convenient place to resolve dependencies.

inject() is particularly useful for:

  • Components
  • Services
  • Functional route guards
  • Functional HTTP interceptors
  • Provider factory functions
  • Field initializers
  • Reusable helper functions running in an injection context

For example, a functional route guard doesn't have a class constructor:

export const authGuard: CanActivateFn = () => {

  const authService = inject(AuthService);

  return authService.isLoggedIn();
};

Here, inject() is the natural way to access AuthService.


3. Full Simple Sample Program

Let's implement the same functionality using inject().

product.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ProductService {

  getProducts(): string[] {
    return [
      'Laptop',
      'Mobile',
      'Keyboard',
      'Mouse'
    ];
  }
}

product.ts

import { Component, inject } from '@angular/core';
import { ProductService } from './product.service';

@Component({
  selector: 'app-product',
  standalone: true,
  templateUrl: './product.html'
})
export class Product {

  private productService = inject(ProductService);

  products: string[] = [];

  constructor() {
    this.products = this.productService.getProducts();
  }
}

product.html

<h2>Products</h2>

<ul>
  @for (product of products; track product) {
    <li>{{ product }}</li>
  }
</ul>

4. Program Explanation

Step 1 — Import inject

import { Component, inject } from '@angular/core';

inject() comes from Angular Core.


Step 2 — Request the Service

Instead of:

constructor(private productService: ProductService) {
}

we write:

private productService = inject(ProductService);

This tells Angular:

Resolve ProductService from the current injection context.


Step 3 — Angular Searches the Injector

Angular's DI system searches for a provider for:

ProductService

Our service has:

@Injectable({
  providedIn: 'root'
})

so Angular can resolve it through the root-level provider.


Step 4 — Use the Service

We can then use it normally:

this.products = this.productService.getProducts();

The overall flow is:

Product Component
       ↓
inject(ProductService)
       ↓
Angular DI
       ↓
Find provider
       ↓
Resolve ProductService
       ↓
Return service instance
       ↓
Component uses service

5. Can We Make the Code Even Simpler?

Yes.

Instead of:

products: string[] = [];

constructor() {
  this.products = this.productService.getProducts();
}

we can initialize the property directly:

export class Product {

  private productService = inject(ProductService);

  products = this.productService.getProducts();
}

So the complete component can be:

import { Component, inject } from '@angular/core';
import { ProductService } from './product.service';

@Component({
  selector: 'app-product',
  standalone: true,
  templateUrl: './product.html'
})
export class Product {

  private productService = inject(ProductService);

  products = this.productService.getProducts();
}

This is concise and common in modern Angular code.


6. Constructor Injection

Constructor injection means dependencies are declared as constructor parameters.

export class Product {

  constructor(private productService: ProductService) {
  }
}

Angular sees:

ProductService

and resolves it through DI.

Conceptually:

Angular creates Product
        ↓
Examines constructor dependency
        ↓
ProductService required
        ↓
Injector resolves ProductService
        ↓
Angular passes service to constructor

7. inject() Injection

With inject():

export class Product {

  private productService = inject(ProductService);
}

Angular resolves the dependency from the current injection context.

Product created by Angular
        ↓
Field initializer executes
        ↓
inject(ProductService)
        ↓
Current Angular injection context
        ↓
Injector resolves ProductService
        ↓
Service returned

8. Constructor Injection vs inject()

Feature Constructor Injection inject()
Syntax Constructor parameter Function call
Example constructor(private s: Service) private s = inject(Service)
Uses Angular DI Yes Yes
Components Yes Yes
Services Yes Yes
Functional guards Not directly Yes
Functional interceptors Not directly Yes
Factory functions Not directly Yes
Field initialization No Yes
Requires constructor Yes No
Modern Angular APIs Supported Very useful
Injection context required Angular constructs class Yes

9. Functional Guard Example

This is one of the most important use cases for inject().

auth.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  isLoggedIn(): boolean {
    return true;
  }
}

auth.guard.ts

import { inject } from '@angular/core';
import { CanActivateFn } from '@angular/router';
import { AuthService } from './auth.service';

export const authGuard: CanActivateFn = () => {

  const authService = inject(AuthService);

  return authService.isLoggedIn();
};

There is no class:

export class AuthGuard

and therefore no constructor is needed.

inject() fits naturally:

const authService = inject(AuthService);

10. Functional HTTP Interceptor Example

The same concept is useful with modern functional interceptors.

import { inject } from '@angular/core';
import { HttpInterceptorFn } from '@angular/common/http';
import { AuthService } from './auth.service';

export const authInterceptor: HttpInterceptorFn = (req, next) => {

  const authService = inject(AuthService);

  // Use authService here

  return next(req);
};

Again:

Functional Interceptor
        ↓
No class constructor
        ↓
inject(AuthService)
        ↓
Angular DI

11. Important: inject() Cannot Be Used Anywhere

This is an important interview point.

inject() must run inside an Angular injection context.

For example, this is valid:

export class Product {

  private service = inject(ProductService);
}

But you shouldn't assume you can call inject() from any arbitrary function at any time.

For example, this can fail:

someMethod() {
  const service = inject(ProductService);
}

because a normal method invocation does not automatically have an active injection context.

Angular can report an error such as:

NG0203: inject() must be called from an injection context

So remember:

inject() works only when Angular has established an injection context.


12. Advantages of inject()

1. Less Constructor Code

Instead of:

constructor(
  private productService: ProductService,
  private authService: AuthService,
  private loggerService: LoggerService
) {}

you can write:

private productService = inject(ProductService);
private authService = inject(AuthService);
private loggerService = inject(LoggerService);

2. Works with Functional APIs

Very useful for:

Functional Guards
Functional Interceptors
Provider Factories
Other DI-aware functions

3. Direct Field Initialization

You can write:

private productService = inject(ProductService);

products = this.productService.getProducts();

without needing a constructor solely for dependency injection.


4. Clear Property Visibility

You can explicitly declare:

private productService = inject(ProductService);

or:

protected productService = inject(ProductService);

5. Good Type Inference

TypeScript understands the returned type:

const service = inject(ProductService);

Here service is inferred as:

ProductService

13. Disadvantages of inject()

Injection Context Requirement

The main restriction is that inject() cannot simply be called anywhere.

It requires an Angular injection context.


Developers Must Understand DI Context

This is straightforward:

private service = inject(ProductService);

But developers need a better understanding of Angular's DI lifecycle when using inject() inside functions and factories.


Mixing Styles Can Reduce Consistency

A project can technically contain:

constructor(private authService: AuthService) {}

and elsewhere:

private authService = inject(AuthService);

Both are valid, but a team may choose conventions to keep code consistent.


14. Which Should We Use?

Both are valid Angular DI techniques.

For normal components and services, you may use either:

constructor(private productService: ProductService) {}

or:

private productService = inject(ProductService);

For modern functional APIs, inject() is particularly useful:

export const authGuard: CanActivateFn = () => {

  const authService = inject(AuthService);

  return authService.isLoggedIn();
};

A useful rule:

Class-based component/service
        ↓
Constructor injection OR inject()


Functional Angular API
        ↓
inject() is usually the natural choice

15. Key Points

  • inject() comes from @angular/core.
  • It retrieves dependencies using Angular's DI system.
  • It provides an alternative to constructor injection.
  • Both constructor injection and inject() use the same underlying DI system.
  • inject() is especially useful with functional guards, interceptors, and provider factories.
  • It can also simplify component and service classes.
  • inject() requires an injection context.
  • Don't call inject() from arbitrary methods and expect it to work.
  • Constructor injection remains fully valid.
  • inject() does not manually create the service; Angular's injector still resolves it.

16. Interview Questions and Answers

1. What is the inject() function in Angular?

inject() is an Angular function that retrieves a dependency from Angular's DI system without requiring the dependency to be declared as a constructor parameter.

private service = inject(ProductService);

2. What is the difference between constructor injection and inject()?

Constructor injection declares dependencies through constructor parameters:

constructor(private service: ProductService) {}

inject() retrieves the dependency directly from the current Angular injection context:

private service = inject(ProductService);

Both use Angular's DI system.


3. Does inject() create a new service every time?

No.

inject() asks Angular's injector to resolve the dependency. Whether Angular returns an existing instance or creates a new one depends on the provider and injector scope.


4. Can inject() be used in components?

Yes.

private productService = inject(ProductService);

5. Can inject() be used in services?

Yes.

@Injectable({
  providedIn: 'root'
})
export class OrderService {

  private productService = inject(ProductService);
}

6. Where is inject() especially useful?

It is especially useful with:

  • Functional route guards
  • Functional HTTP interceptors
  • Provider factories
  • Field initializers
  • Other Angular APIs running in an injection context

7. Can inject() be called from any method?

No. It must execute within a valid Angular injection context. Calling it from an arbitrary method can produce an NG0203 error.


8. Is constructor injection deprecated?

No. Constructor injection remains supported. inject() is another DI mechanism and is particularly convenient with Angular's functional APIs.


Interview Shortcut

Constructor Injection

constructor(private service: ProductService) {}

             vs

inject()

private service = inject(ProductService);


Both
 ↓
Angular DI
 ↓
Injector
 ↓
Provider
 ↓
ProductService

Constructor injection declares dependencies through constructor parameters, whereas inject() retrieves dependencies directly from Angular's current injection context. Both use Angular's Dependency Injection system.

← Back to Articles