---
title: "Dependency injection, providers, and application boundaries"
chapter: "03"
---

# Dependency injection, providers, and application boundaries

Angular dependency injection supplies services according to a hierarchical
provider tree.

## inject and tokens

```ts
export const API_BASE_URL = new InjectionToken<string>('API_BASE_URL');

@Injectable({ providedIn: 'root' })
export class OrdersApi {
  private http = inject(HttpClient);
  private baseUrl = inject(API_BASE_URL);
}
```

Use class tokens for stable services and `InjectionToken` for configuration,
interfaces, factories, and multi-provider extension points.

## Provider scope

Root providers are shared for the application lifetime. Route providers create
a feature-scoped instance. Component providers create a subtree instance.
Scope is architecture: it decides state sharing, cleanup, and test boundaries.

## Provider forms

`useClass`, `useValue`, `useFactory`, and `useExisting` express construction or
aliasing. Multi providers collect extensions such as interceptors.

## Injection context

`inject()` works in an injection context—constructors, field initializers,
provider factories, and APIs that establish one. It is not a global service
locator callable anywhere.

## Environment configuration

Compile-time environment replacement is not enough for one immutable image
across environments. Consider loading validated runtime configuration before
bootstrap or serving a configuration endpoint.

## Avoid god services

A service should own a coherent responsibility: HTTP adapter, application
workflow, state store, analytics port, or browser capability. Do not put every
feature's state into one root singleton.

## Feynman check

The injector is a tree of cupboards. Angular looks in the nearest cupboard and
then walks upward. Explain why the same service token can yield different
instances on two routes.
