Chapter 5.3 โ€” inject() vs Constructor Injectionโ˜• 12 min

inject() vs Constructor Injection

Two ways to inject dependencies in Angular. Understand both and know when to use which.

01Constructor Injection (Old Way)

Constructor injection is the traditional way Angular provides dependencies to a class. You list all dependencies as constructor parameters, and Angular reads the TypeScript parameter types at runtime to know what to inject. This has been the standard since Angular 2.

While it works perfectly fine, it has limitations โ€” you can only use it inside class constructors, and the constructor gets cluttered when you have many dependencies.

02Field Injection with inject() (New Way)

The inject() function, introduced in Angular 14, lets you declare dependencies as class field initializers instead of constructor parameters. Each call to inject() retrieves one dependency.

This keeps the constructor clean and makes each dependency declaration independent.

03Why inject() is Better

The inject() function has several advantages over constructor injection:

  • Works in more places: field initializers, factory functions, functional guards, interceptors, and standalone component factories
  • Cleaner constructor: constructor stays focused on initialization logic, not dependency declarations
  • Conditional injection: you can conditionally inject dependencies using if statements
  • Better with signals: works naturally alongside signal declarations in class fields
  • Tree-shakeable: unused dependencies can be more easily identified by the compiler
04Where Each Works

Here is a comparison of where each injection method works:

LocationConstructor Injectioninject()
Component class constructorโœ“โœ“
Service class constructorโœ“โœ“
Class field initializerโœ–โœ“
Functional guardโœ–โœ“
Functional interceptorโœ–โœ“
Factory functionโœ–โœ“
Pipe classโœ“โœ“
setTimeout / event handlerโœ–โœ–

Note: inject() must be called in an injection context. You cannot call it inside event handlers, setTimeout, or plain functions outside of Angular's DI context.

05Migration Guide

Migrating from constructor injection to inject() is straightforward. Here is a step-by-step guide:

Step 1: Replace each constructor parameter with a field initializer

Step 2: If constructor has non-DI logic, keep the constructor for that

Step 3: Move any initialization that depends on injections to the field or ngOnInit

Migrate one service at a time. There is no rush โ€” both patterns work perfectly together.

Key Takeaways

  • โœ… Constructor injection lists dependencies in constructor parameters (traditional way)
  • โœ… inject() declares dependencies as class field initializers (modern way)
  • โœ… inject() works in more places: guards, interceptors, factories, field initializers
  • โœ… inject() keeps the constructor clean for non-DI initialization logic
  • โœ… Either pattern works โ€” pick one and be consistent across your codebase
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase