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

inject() retrieves a dependency from the injector that is active at the moment the call runs, and it works only inside an injection context. In practice that means class constructors, field initializers on Angular-managed classes, provider factory functions, and functions that Angular itself runs in that context. If you call it from an ordinary method or a lifecycle hook such as ngOnInit, Angular raises error NG0203. In most cases the fix is to move the call up into a field initializer or the constructor. The sections below cover the valid locations, the optional-injection typing, the workarounds for code outside a context, and the official migration from constructor parameters.

What inject() does

Angular’s API reference describes the function in one line: “Injects a token from the currently active injector.” (Angular inject API reference). The “currently active injector” is the one Angular has chosen for the code that is running, which is why the function depends on timing and location rather than on an import alone. Importing inject from @angular/core is necessary but not sufficient; the call also has to happen while an injection context exists.

Where inject() is allowed

Angular’s injection context guide lists the situations where the call succeeds (Angular injection context guide). In summary, a call is valid when it runs in:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • the constructor of a class that Angular instantiates through its dependency injection system;
  • a field initializer of such a class, which runs as part of construction;
  • a provider factory function or an InjectionToken factory function;
  • any function called while an injection context is active. Router guard functions are a common example of APIs that execute inside one.

Where inject() fails

An instance method or lifecycle hook runs after Angular has already created the instance, so no injection context is active at that point. The call raises NG0203 (Angular NG0203 error reference). The following pattern fails:

export class CartComponent implements OnInit {
  ngOnInit() {
    const cart = inject(CartService); // NG0203
    cart.load();
  }
}

Moving the lookup into a field initializer makes it valid, because field initializers run during construction:

export class CartComponent implements OnInit {
  private cart = inject(CartService);

  ngOnInit() {
    this.cart.load();
  }
}

Return values and options

The function is overloaded for two kinds of token. For a provider token, a standard injection returns the resolved value. Passing the optional flag changes the return type, because a missing provider then yields null rather than a value. For a host attribute token, the call returns a string when the attribute is present; its optional overload can return null. The options object corresponds to lookup strategies such as host, self, and skip-self behavior, as well as optional lookup (Angular inject API reference).

Call form Return type When no value is found
inject(TOKEN) (provider token) The resolved value of the token’s type The optional-case null does not apply; the reference does not describe a null result for this form
inject(TOKEN, {optional: true}) The resolved value, typed to include null null
Host attribute injection (standard) string Present only when the attribute exists on the host element
Host attribute injection (optional overload) string or null null

When you write examples or review code, make optionality explicit and keep the nullable type in the declaration. A field typed as the non-null service while the lookup can return null moves the failure to a later property access.

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

Running inject() outside a context

Sometimes a function that needs dependencies is called from code that has no injection context, such as a helper invoked from a plain callback. Angular’s guide describes runInInjectionContext for this case, which takes an injector, typically an EnvironmentInjector from the environment hierarchy outside the component tree (Angular EnvironmentInjector API reference). The procedure is:

  1. Obtain an injector that is available to the code, for example one passed in as a parameter or one injected into a class that is already constructed in a valid context.
  2. Wrap the dependency lookup in runInInjectionContext(injector, () => ...), calling inject() inside the callback.
  3. Keep the lookup synchronous. The context exists only while the callback is running, so do not schedule inject() in a later callback or place it after an await.

The EnvironmentInjector.runInContext method is deprecated, and Angular’s API points developers to the standalone runInInjectionContext function instead (Angular EnvironmentInjector API reference).

Diagnosing NG0203

NG0203 means that inject() ran outside an allowed injection context. Work through these checks in order:

  • Read the stack trace to find the line that called inject(), then identify which function or method contains it.
  • If that function is an instance method or lifecycle hook, move the lookup to a field initializer or the constructor.
  • If the code is a helper that must run later, pass an injector into it and use runInInjectionContext around the synchronous lookup.
  • If the call is in a test that needs a DI context, use TestBed.runInInjectionContext rather than calling the function directly.

The official error page for NG0203 is the reference for the exact condition (Angular NG0203 error reference).

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Migrating constructor injection

Angular provides a schematic that converts eligible constructor parameters to inject() calls. Run it with:

ng generate @angular/core:inject

The schematic replaces eligible constructor parameters with field declarations such as private service = inject(MyService), and optional parameters with calls such as inject(DI_TOKEN, {optional: true}) (Angular inject migration guide). Review the diff before committing, since the schematic only rewrites parameters it judges eligible.

migrateAbstractClasses

This option is disabled by default. Angular cannot verify that constructor parameters of abstract classes are injectable, so migrating them can introduce breakage. Leave abstract classes on constructor injection unless you have checked each parameter manually.

backwardsCompatibleConstructors

Some decorated class hierarchies depend on a constructor signature that subclasses still call. This option keeps that signature so inheritance keeps working. The cost is extra generated code, and the migrated class is not as clean as a pure inject() version.

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

nonNullableOptional

Older code sometimes typed an @Optional() parameter without null. This option preserves that non-null type by adding a non-null assertion. Optional injection can return null, so the assertion can hide a real missing-value case. Enable it only when that behavior is intentional, and otherwise let the nullable type show up in the code so each use can be checked.

inject() in tests

Angular also exports a separate inject helper from @angular/core/testing. It injects dependencies into beforeEach() and it() blocks and is meant only for tests. Application code should import inject from @angular/core (Angular testing inject API reference). Keep the two imports distinct so that a test helper does not end up in production source.

“

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.