All topics
Servicesbeginner

Singleton Services

Explain what makes a service a singleton in Angular and why that matters for shared state across components.

A singleton service is one that Angular's injector creates exactly once and hands out that same shared instance to every class that injects it, and it's the default outcome of providedIn: 'root' — the most common way services are registered in modern Angular. Interviewers ask about this early because it underpins a huge amount of practical Angular architecture: any time two unrelated components need to share state or coordinate without a direct parent-child relationship, a singleton service is almost always the answer.

It's like a single shared office thermostat rather than individual room heaters — everyone in the building is reading from and adjusting the same one, so a change one person makes is instantly visible to everyone else.

Key Concepts

1
The mechanism is straightforward: the injector caches the constructed instance the first time it's requested, and every subsequent injection of that same token returns the cached instance rather than constructing a new one. This is what allows, for example, a CartService injected into a header component and a checkout page to reflect the exact same cart state, without any manual event bus or shared parent state passing.
CartService
2
A common interview trap is assuming a service is always a singleton just because it's @Injectable() — that's only guaranteed with providedIn: 'root' (or an equivalent root-level provider registration); a service registered in a component's own providers array is a singleton only within that component's subtree, and a new component instance (say, opening the same route twice) gets its own separate instance.
@Injectable()providedIn: 'root'providers
3
A solid answer also connects singleton services to state management more broadly: many small-to-medium Angular apps don't need NgRx or a dedicated state library at all, because a providedIn: 'root' service holding Signals or a BehaviorSubject already gives you a simple, effective, app-wide reactive store.
providedIn: 'root'BehaviorSubject