Angular 22 Resource Additions Leave Mutations to Community Libraries
Angular 22 introduces stable resource() and httpResource() for reads, while @ngsignal/mutation version 0.6.0 tackles Signal-native writes.

Stock photo for illustration only, not from the actual event
- Angular 22 officially introduces resource() and httpResource() for data fetching but excludes writes.
- @ngsignal/mutation provides a Signal-native alternative for handling write operations without stores or caches.
- The library handles concurrency, error states, lifecycles, and SSR without relying on RxJS in its core.
- Version 0.6.0 supports Angular 21 and 22, featuring explicit queue management and mutation states.
Angular's reactivity model reaches a new milestone as resource() and httpResource() become stable features in Angular 22. Fetching data has become straightforward by declaring dependencies and reading resulting signals while Angular handles the underlying reactive plumbing. However, Angular deliberately refrains from using resource() for write operations, raising the question of what a Signal-native write API should look like.
This is the exact problem that the @ngsignal/mutation library aims to solve. Its API mirrors Angular's resource family to make write operations feel native to Angular resources without requiring an entirely new data layer. Rather than bloating the codebase, it provides a behavior contract for writes covering state, errors, lifecycles, SSR, and concurrency management.
While the resource API focuses on reads and the httpResource guide recommends HttpClient for POST and PUT requests according to the Resource RFC, cancellation holds entirely different meanings for reads versus writes. Stale reads can be discarded when newer fetches start, but write operations might have already altered server-side data. For instance, executing a POST /orders request where the server creates the order before the browser stops waiting means you can abort the client request, but you cannot undo actions already processed by the server.
"This result is stale" does not mean "this write must be cancelled."
Erwan Raulo
The @ngsignal/mutation library takes the opposite philosophy, featuring no store, no cache, no provider, and no RxJS in its core. It offers just a compact Signal-native primitive for writes. A mutation functions simply by transforming inputs into a Promise, while mutation() exposes read-only signals for status, value, error, input, and derived states like isPending() and isSuccess() for direct template binding.
From a modern web architecture perspective, building robust state machines for data mutations is often one of the trickiest parts of frontend development due to race conditions, cancellation rules, and pending states. Relying on custom boilerplate for every application leads to unnecessary complexity. Utilizing a focused, Signal-native primitive helps maintain clean code boundaries while staying perfectly aligned with Angular's core reactive philosophy.

Stock photo for illustration only, not from the actual event
Furthermore, httpMigration() extends HTTP handling capabilities similarly to httpResource(), supporting file uploads with progress bars, response headers, and blob variants for server-generated documents. Initiating a new mutate() call does not automatically abort previous ones unless reset() or destruction occurs, assigning generation numbers so only the latest execution writes the signals. It also introduces queue concurrency strategies, ensuring tasks execute sequentially once previous operations settle.
Source: Dev.to
Found something wrong in this article? Report an issue with this article
Comments
Leave a Comment