NgRx, the reactive state management framework for Angular, has released version 22, shipping utilities for customising Angular's resource API, dynamic deep signals for union types, a new SignalStore typing helper and ESLint v10 compatibility.
The main new addition is resource extensions, delivered through a new experimental @ngrx/signals/resource entry point. Angular's resource and httpResource APIs reset value() to undefined while reloading and throw when read in an error state. Resource extensions wrap an existing resource and patch only those behaviours, while preserving the original resource type.
Four built-in extensions are included, alongside a provideResourceExtensions function that registers defaults at application, route or component level. In the original RFC, Marko Stanimirović explained that changing the error behaviour is also a prerequisite for deeper SignalStore integration, as "once a resource enters the error state, any subsequent patchState call will throw because it reads value() internally".
The proposal was well received, with Manfred Steyer replying "Love it!" and suggesting an activation signal, while another commenter asked for parity with SolidJS's createResource, such as access to the current value inside the loader.
A community roundup on DEV noted that similar behaviour could be built with Angular's snapshot() and extra state logic, but "with Resource Extensions, you stay on the resource itself", keeping the value writable and retaining the more specific httpResource type.
TanStack Query for Angular offers similar previous-data retention when query keys change through placeholderData: keepPreviousData. Separately, the community NgRx Toolkit’s withResource has supported non-throwing undefined value
and previous value
; error-handling strategies for SignalStore since v20.6.0.
Version 22 also makes deep signals dynamic. Previously, a state slice typed as a union, the natural way to model "not loaded yet", collapsed into a single flat Signal. Now each object literal member gets its own DeepSignal, reachable after narrowing with an in check.
A new SignalStoreFeatureType utility extracts the state and members of a feature factory so custom features can reuse them as input types, rather than redeclaring them by hand. Elsewhere, @ngrx/store-devtools gains an actionCreators option for dispatching from Redux DevTools, and @ngrx/eslint-plugin now supports ESLint v10 while dropping ESLint v8 and the legacy .eslintrc format. The documentation site also gains a light theme.
Developers upgrading need Angular 22, TypeScript 6.0 and RxJS ^6.5 or ^7.5, and can run ng update @ngrx/store@22, or ng update @ngrx/signals@22 for SignalStore-only projects. Most breaking changes have automated migrations, detailed in the v22 migration guide and changelog. Teams should also note that Angular 22 changed resource timing, with one developer reporting test failures that were subsequently added to Angular's release notes as a breaking change.
In the Hacker News thread for Angular v22, one user wrote:
NGRX Signals is the new way and its lovely. Instead of having 5 files to get state hooked up, its usually 1 file and all/most functionality is co-located.
Although another observed that:
Modern Angular is MUCH nicer to use than the v2 days (or even the v4 days when I first started working with it). A lot of the required boilerplate is unnecessary nowadays. And even RxJS and NgRX are becoming less and less necessary to use too, which is great.
NgRx is an open-source, community-driven framework for building reactive Angular applications, providing global state management with Store and Effects alongside the signal-based SignalStore. It is sponsored by Nx and CodeRabbit, and its source is available on GitHub.
About the Author
Daniel Curtis
Show moreShow less
