← Back to list

I cut 40% of my NgRx Signal Store boilerplate — here’s the 5 utilities I extracted

Every Signal Store in our monorepo started the same way. Fifty-plus lines of ceremony before a single line of business logic. Loading…

Harsh Mathur · 2026-04-12 21:09 · 0 claps · 2.4 min read
#angular #typescript #web-development #ngrx #frontend-engineering
Open on Medium ↗
Wiki topics: 🌐 · Web Development

I cut 40% of my NgRx Signal Store boilerplate — here’s the 5 utilities I extracted

Every Signal Store in our monorepo started the same way. Fifty-plus lines of ceremony before a single line of business logic. Loading flags, error messages, pagination math, search pipes, entity sync — all copy-pasted from the last store with minor tweaks. Twenty stores later, I had twenty copies of the same patterns drifting apart.

So I extracted them. Five composable signalStoreFeature utilities, each replacing a chunk of repetitive code with a single function call. The result is signalstore-toolkit.

The problem: stores that are 60% scaffolding

Here is a stripped-down version of what a typical store looked like before. This handles one entity with loading state, error handling, and pagination:

That is around 35 lines of infrastructure and maybe 0 lines of actual domain logic. Every new store repeated this. Every one was slightly different in the ways that cause bugs.

The fix: five composable features

withRequestStatus — the hero cut

This was the biggest win. Every store had its own isLoading, isError, errorMessage triple, its own setPending/ setFulfilled/ setError methods. withRequestStatus() replaces all of it:

// Before: 15 lines of state + methods per store // After: withRequestStatus ()

One line. You get requestStatus, isPending, isFulfilled, error, setPending, setFulfilled, setError, and resetStatus - all typed, all consistent across every store.

withEntitySync — real-time entity reconciliation

If you work with live data — WebSocket updates, polling, server-sent events — you need to reconcile incoming entities with what is already in the store. withEntitySync() gives you syncAll, upsertOne, liveUpdate (parses JSON and upserts), and removeOne:

The liveUpdate method is particularly useful. Point it at a WebSocket message and it handles JSON parsing and entity upsert in one call.

withPagination — no more page math

Page offset calculations, hasNextPage guards, total page derivation - all computed, all reactive:

withPagination () // Gives you: currentPage, pageSize, total, totalPages, // hasNextPage, hasPreviousPage, pageOffset, // setPage, nextPage, previousPage, setPageSize, setPageResult

createApiMethod — factory for rxMethod + loading state

This is not a store feature but a factory function. It wires up rxMethod with tapResponse, manages loading/error state on the store, and validates the API response shape. You configure the operator ( switchMap for reads, concatMap for writes):

That replaces roughly 30 lines of rxMethod + pipe + tapResponse + manual setPending/ setFulfilled/ setError wiring per API call.

withSearchFilter — declarative search + sort

Composes after withEntities(). You declare which fields to search and how to sort:

The composed store

Here is the same product store from above, rebuilt with all five utilities:

All the infrastructure is handled. What remains is the domain-specific wiring: which API to call, what to do with the response. That is it.

How it compares to @angular-architects/ngrx-toolkit

The two libraries are complementary, not competing. @angular-architects/ngrx-toolkit focuses on DevTools integration, undo/redo, Redux connector, and data service patterns. signalstore-toolkit focuses on per-operation status tracking, entity live-update reconciliation, the API method factory with app-level response checking, and search/filter pipelines. There is no overlap - you can use both in the same store.

Install

npm install signalstore-toolkit

Peer deps: Angular 17+, @ngrx/signals 17+, RxJS 7+. The @ngrx/operators package is optional and only needed if you use createApiMethod.

These patterns were extracted from a production Angular monorepo running 20+ Signal Stores with gRPC-web as the transport layer. They have been stable in production for months.

npm: signalstore-toolkit GitHub: harsh04/signalstore-toolkit

Feedback welcome.

Originally published at https://dev.to on April 12, 2026.


메타데이터
post_id
7d00545ec982
slug
i-cut-40-of-my-ngrx-signal-store-boilerplate-heres-the-5-utilities-i-extracted-7d00545ec982
url
https://medium.com/@harshmathur.04/i-cut-40-of-my-ngrx-signal-store-boilerplate-heres-the-5-utilities-i-extracted-7d00545ec982
canonical_url
https://medium.com/@harshmathur.04/i-cut-40-of-my-ngrx-signal-store-boilerplate-heres-the-5-utilities-i-extracted-7d00545ec982
author_url
https://medium.com/@harshmathur.04
status
ok
fetched_at
2026-06-20 20:29:01