"State management" in Angular isn't a single tool, it's a spectrum from a simple component field to a full-blown store. This lesson maps out the options so you can choose deliberately rather than reaching for the heaviest tool by default.
What Is Application State?
State is any data that changes over time and affects what your UI shows: a form's current values, whether a modal is open, a fetched list of orders, or the currently logged-in user. Different kinds of state naturally live at different scopes.
Angular doesn't force a single state management pattern. Instead, it gives you building blocks, component fields, signals, services, and (optionally) NgRx, that you combine based on how widely a piece of state needs to be shared.
// component-local: only this component cares
isMenuOpen = signal(false);
// shared across components: a service
@Injectable({ providedIn: 'root' })
export class CartService {
items = signal<string[]>([]);
}
Both examples use signals, the difference is scope: a component field vs a shared, injectable service.
The State Management Spectrum
Component field/signal -> state used by one component only
Service with signals -> state shared across several components
NgRx / global store -> state shared app-wide with strict, traceable updates
Start with the simplest option (a component field) and move up the spectrum only as sharing needs grow.
A service with signals covers the vast majority of "shared state" needs without extra libraries.
NgRx (or similar) becomes worthwhile for large apps with complex, cross-cutting state and strict traceability needs.
Mixing levels is normal: most real apps use component state, service state, and (sometimes) NgRx together.
State Management Options Cheatsheet
Choosing the right level of state management for a given feature.
Scope
Tool
Example
Single component
Component field/signal
Whether a dropdown is open
A few related components
A shared parent component's state, passed via inputs
A multi-step wizard's current step
Across unrelated components
An injectable service (with signals or RxJS)
Shopping cart contents
Whole application, complex flows
NgRx or a similar store
Large e-commerce checkout, complex dashboards
Server-fetched data with caching
Signals + services, or a data-fetching library
Product catalog, user profile
Avoid Premature Complexity
A very common mistake is reaching for NgRx (or another heavy state library) on day one, before the application has any state complexity that actually needs it. Most Angular apps can go a long way with just component fields and a handful of well-designed services.
Start with component fields/signals for anything local to one component.
Move state into a service the moment two or more unrelated components need to share it.
Only introduce NgRx (or similar) once state changes become genuinely hard to trace with services alone.
Signals vs RxJS for State
Signals are Angular's newer, simpler primitive for synchronous, reactive state, ideal for most component and service state. RxJS remains the right tool for asynchronous streams, especially ones involving timing (debouncing), combining multiple sources, or cancellation.
Use Case
Better Fit
Simple synchronous shared state (cart, theme, current user)
NgRx (and similar libraries) shine when state changes are genuinely complex, coming from many sources, needing strict auditability, or requiring time-travel debugging. If your app's state can be described with a handful of clearly-owned services, you likely don't need it yet.
Many different user actions and API responses affect the same piece of state.
You need reliable time-travel debugging or strict action-based traceability.
Multiple teams work on the same large codebase and need enforced, consistent state update patterns.
Common Mistakes
Introducing NgRx before an application has state complexity that actually benefits from it.
Putting truly global state (like the logged-in user) directly on a single component instead of a shared service.
Duplicating the same piece of state in multiple components instead of a single shared source of truth.
Mixing signals and RxJS inconsistently for the same piece of state without a clear reason.
Key Takeaways
Angular state management spans a spectrum: component fields, shared services, and (optionally) NgRx.
Start with the simplest option and move up the spectrum only as sharing/complexity needs grow.
Signals suit most synchronous shared state; RxJS suits asynchronous, time-based, or cancellable state.
NgRx is valuable for large, complex state graphs, not a required default for every Angular app.
Pro Tip
Before reaching for a state management library, ask: "Could a single, well-named service with a signal solve this?" For the majority of Angular features, the answer is yes, and it comes with far less boilerplate than a full store.
You now understand the Angular state management spectrum. Next, focus specifically on Component State, the simplest and most common level.