← Retour au blog
state-managementangularngrxsignalsarchitecture

State management: When NOT to use NgRx (and what to choose instead)

NgRx has become almost reflexive in ambitious Angular teams. The moment an application grows beyond a few screens, someone inevitably says "we should use NgRx." But that's a strategic mistake. NgRx solves one very specific problem: managing complex global state with synchronous and asynchronous actions, complete traceability, and custom middleware. If your application doesn't have these constraints, NgRx becomes boilerplate overhead and unnecessary friction for your team. The cognitive cost of NgRx—actions, reducers, effects, selectors, and the entire Redux philosophy—is only justified if you derive real benefits. For most modern Angular applications, you're better off starting with something simpler and migrating only if you hit genuine complexity walls.

When NgRx becomes dead weight

Here are the red flags: your global state fits in a few simple variables (logged-in user, theme, language, notifications). You don't need temporal traceability or action replay. Your business logic doesn't involve complex cascading or parallel API call flows. Your team is small and has little Redux experience. You're building an MVP or prototype that needs to ship fast. In all these cases, NgRx is overhead. You spend 30% of your time writing Redux boilerplate instead of solving real business problems. Actions become endless enumerations. Reducers fill with verbose default cases. And NgRx tests require complex infrastructure with MockStore, provideMockStore, and fixture setup. The real danger: you end up doing half-baked NgRx without real discipline, producing code more confusing than a straightforward service-signal architecture.

The lightweight alternative: services + Signals

The combination of services and Signals (the new Signals in Angular 17+) covers 95% of everyday use cases. A service exposing signals provides reactive, traceable, and testable state without heavy framework overhead. Concrete example: a shopping cart service. You create a CartService with an internal signal for items and public methods to add, remove, clear. Components access the signal via cartService.items(). When an item changes, Angular triggers reactivity automatically via computed or effects. No actions, no reducers, no selectors. Just readable TypeScript.

const cart = signal<CartItem[]>([]); const total = computed(() => cart().reduce((sum, item) => sum + item.price * item.quantity, 0));

addItem(item: CartItem) { cart.update(items => [...items, item]); effect(() => console.log('Total updated:', total())); }

This pattern works for 80% of modern Angular applications. The advantages: zero boilerplate, trivial debugging (signals are inspectable in Angular DevTools), and state remains testable with simple spies. You can even compose multiple services by injecting them into each other if you need coordination. Unlike NgRx, Signals play natively with Angular's reactivity system without an extra abstraction layer. You get reactivity without the framework tax.

When NgRx becomes justified

If you have a financial application with concurrent transactions, a real-time platform with WebSocket and multiple async data streams, or a complex dashboard where user actions trigger cascading side effects, NgRx starts making sense. You also need NgRx if your team requires complete state mutation traceability for compliance or debugging. NgRx DevTools let you replay every action, export history, and debug timing bugs that would be impossible to reproduce otherwise. Another justification: your global state is genuinely massive and fragmented—multiple state domains (user, products, orders, notifications) evolving independently but needing synchronization. A well-structured NgRx store with feature stores becomes more maintainable than a forest of services in this scenario.

The common pitfall: NgRx "by habit"

The most common pitfall is adopting NgRx because the team used it before, or because you fear future complexity might require it. That's dangerous predesign. You end up with a 500-line NgRx store for 3 simple actions. Junior developers spend more time understanding NgRx structure than fixing real bugs. And when complexity finally arrives, you already have awkward NgRx code polluting the codebase. The right pattern: start with services + Signals. If you reach a point where you think "we need action traceability," "too many services talking to each other," or "we must replay flows," then migrate to NgRx. But that migration often never becomes necessary. Better simple working code than complex anticipatory code.

The real decision criteria

Ask yourself these questions before adding NgRx. Does your team master Redux and the subscription pattern? Do you have complex async actions with error handling and retry logic? Does your global state change more than 100 times per second requiring render optimization? Do you have traceability or audit requirements? Are multiple teams working on the same store? If you answer yes to at least two, NgRx is probably justified. If you answer no, services + Signals suffice. There's no shame in not using NgRx. The world's biggest Angular applications use a mix: NgRx for critical domains (auth, orders), services + Signals for everything else (UI state, notifications, theme). That's architectural pragmatism.

Conclusion: pragmatism over dogma

State management isn't binary. There's a spectrum: pure Signals, services with Signals, RxJS Subject/BehaviorSubject, Akita, NgRx. Choosing NgRx because it's "professional" or "scalable" is a mistake. Choosing NgRx because your problem genuinely demands it is a good decision. Always start with the simplest approach. You can refactor to NgRx in 2-3 days if truly necessary. You cannot refactor away from NgRx without pain if you've built 10,000 lines of unnecessary NgRx code. For 2026, the trend is clear: small teams abandon NgRx for Signals + services, and mature teams keep it only where it genuinely adds value. Be honest about your application's real complexity. Your future self will thank you.

Développeur Angular & Mobile freelance — Strasbourg.

© 2026 Emilien Pons — Tous droits réservés.Conçu avec Angular, PrimeNG et ❤️