# NgRx Signal Store vs NgRx classico nel 2026: quale scegliere per il tuo progetto Angular? > Confronto approfondito tra NgRx Signal Store e NgRx classico nel 2026. Architettura, performance, boilerplate e strategie di migrazione per la gestione dello stato in Angular. - Published: 2026-07-11 - Updated: 2026-07-11 - Author: SharpSkill - Reading time: 5 min --- NgRx Signal Store rappresenta un cambiamento fondamentale nella gestione dello stato Angular, sostituendo il tradizionale pattern ispirato a Redux basato su actions, reducers e selectors con un approccio reattivo basato sui signals. Questo confronto esamina entrambe le soluzioni per aiutare gli sviluppatori Angular a prendere decisioni architetturali informate nel 2026. > **Guida rapida alla scelta** > > Utilizzare **Signal Store** per la gestione dello stato a livello di feature e applicazioni di media complessità dove la riduzione del boilerplate è importante. Utilizzare **NgRx classico** per applicazioni enterprise che richiedono audit trail rigorosi, side effects complessi e debugging avanzato con DevTools. ## Comprendere le differenze architetturali NgRx classico segue il [pattern Redux](https://redux.js.org/understanding/thinking-in-redux/three-principles): le actions descrivono eventi, i reducers producono nuovo stato immutabile, e i selectors estraggono dati. Ogni cambiamento di stato passa attraverso una pipeline prevedibile e tracciabile. Signal Store adotta un approccio diverso. Invece di inviare actions attraverso reducers, lo stato risiede in signals reattivi. Gli aggiornamenti avvengono tramite metodi che chiamano `patchState()`, e i valori derivati provengono da computed signals invece che da selectors memorizzati. | Aspetto | NgRx classico | Signal Store | |---------|---------------|---------------| | Modello mentale | Redux/Flux | Servizi reattivi | | Boilerplate | Alto (actions, reducers, selectors, effects) | Basso (state, metodi, computed) | | Reattività | RxJS Observables | Angular Signals | | DevTools | Redux DevTools completi | Signal Store DevTools (via plugin) | | Curva di apprendimento | Ripida | Moderata | | Dimensione bundle | Maggiore | Minore | Per gli sviluppatori già familiari con [Angular Signals](/technologies/angular/interview-questions/angular-signals), Signal Store risulta un'estensione naturale delle primitive reattive del framework. ## NgRx classico: il pattern Redux in Angular NgRx classico organizza la gestione dello stato attorno ad actions, reducers, selectors ed effects. Questa separazione garantisce prevedibilità a costo di maggiore verbosità. ```typescript // books.actions.ts import { createActionGroup, emptyProps, props } from '@ngrx/store'; import { Book } from './book.model'; export const BooksActions = createActionGroup({ source: 'Books', events: { 'Load Books': emptyProps(), 'Load Books Success': props<{ books: Book[] }>(), 'Load Books Failure': props<{ error: string }>(), 'Add Book': props<{ book: Book }>(), 'Remove Book': props<{ id: string }>(), }, }); ``` L'API `createActionGroup` raggruppa actions correlate sotto un'unica source, migliorando la leggibilità nei DevTools e riducendo il boilerplate rispetto alle chiamate individuali di `createAction`. ```typescript // books.reducer.ts import { createReducer, on } from '@ngrx/store'; import { BooksActions } from './books.actions'; import { Book } from './book.model'; export interface BooksState { books: Book[]; loading: boolean; error: string | null; } const initialState: BooksState = { books: [], loading: false, error: null, }; export const booksReducer = createReducer( initialState, on(BooksActions.loadBooks, (state) => ({ ...state, loading: true, error: null, })), on(BooksActions.loadBooksSuccess, (state, { books }) => ({ ...state, books, loading: false, })), on(BooksActions.loadBooksFailure, (state, { error }) => ({ ...state, loading: false, error, })) ); ``` I reducers rimangono funzioni pure che restituiscono nuovi oggetti stato. La funzione `on()` gestisce il matching delle actions e gli aggiornamenti dello stato in modo conciso. ```typescript // books.selectors.ts import { createFeatureSelector, createSelector } from '@ngrx/store'; import { BooksState } from './books.reducer'; export const selectBooksState = createFeatureSelector('books'); export const selectAllBooks = createSelector( selectBooksState, (state) => state.books ); export const selectBooksLoading = createSelector( selectBooksState, (state) => state.loading ); export const selectPublishedBooks = createSelector( selectAllBooks, (books) => books.filter((book) => book.published) ); ``` I selectors forniscono la memoizzazione automaticamente. Il selector `selectPublishedBooks` ricalcola solo quando l'array books cambia, rendendo le letture efficienti anche in store frequentemente aggiornati. ## NgRx Signal Store: gestione dello stato signals-first Signal Store consolida stato, valori computed e metodi in un unico servizio iniettabile. La [documentazione ufficiale NgRx](https://ngrx.io/guide/signals/signal-store) lo descrive come una "soluzione completa per la gestione dello stato con supporto nativo per Angular Signals". ```typescript // books.store.ts import { computed, inject } from '@angular/core'; import { patchState, signalStore, withComputed, withMethods, withState } from '@ngrx/signals'; import { BooksService } from './books.service'; import { Book } from './book.model'; interface BooksState { books: Book[]; loading: boolean; error: string | null; } const initialState: BooksState = { books: [], loading: false, error: null, }; export const BooksStore = signalStore( { providedIn: 'root' }, withState(initialState), withComputed(({ books }) => ({ publishedBooks: computed(() => books().filter((book) => book.published)), totalBooks: computed(() => books().length), })), withMethods((store, booksService = inject(BooksService)) => ({ async loadBooks() { patchState(store, { loading: true, error: null }); try { const books = await booksService.getAll(); patchState(store, { books, loading: false }); } catch (error) { patchState(store, { loading: false, error: 'Failed to load books' }); } }, addBook(book: Book) { patchState(store, ({ books }) => ({ books: [...books, book] })); }, removeBook(id: string) { patchState(store, ({ books }) => ({ books: books.filter((book) => book.id !== id), })); }, })) ); ``` L'intera gestione dello stato di una feature sta in un unico file. Le proprietà dello stato diventano automaticamente signals, i computed signals sostituiscono i selectors, e i metodi sostituiscono il dispatch delle actions. ## Gestione delle entità con withEntities Entrambi gli approcci supportano le collezioni di entità, ma la feature `withEntities` di Signal Store riduce drasticamente il codice. ```typescript // books-entity.store.ts import { computed, inject } from '@angular/core'; import { patchState, signalStore, withComputed, withMethods } from '@ngrx/signals'; import { addEntity, removeEntity, setAllEntities, updateEntity, withEntities, } from '@ngrx/signals/entities'; import { BooksService } from './books.service'; import { Book } from './book.model'; export const BooksEntityStore = signalStore( { providedIn: 'root' }, withEntities(), withComputed(({ entities }) => ({ publishedBooks: computed(() => entities().filter((book) => book.published)), })), withMethods((store, booksService = inject(BooksService)) => ({ async loadBooks() { const books = await booksService.getAll(); patchState(store, setAllEntities(books)); }, addBook(book: Book) { patchState(store, addEntity(book)); }, updateBook(id: string, changes: Partial) { patchState(store, updateEntity({ id, changes })); }, removeBook(id: string) { patchState(store, removeEntity(id)); }, })) ); ``` La feature `withEntities` fornisce automaticamente i signals `ids`, `entityMap` e `entities`. Gli updater per entità come `addEntity`, `removeEntity` e `updateEntity` gestiscono le mutazioni della collezione. ## Custom Store Features per la riusabilità La funzione `signalStoreFeature` di Signal Store permette di estrarre logiche trasversali e riutilizzarle tra diversi store. ```typescript // with-request-status.ts import { computed } from '@angular/core'; import { signalStoreFeature, withComputed, withState } from '@ngrx/signals'; type RequestStatus = 'idle' | 'pending' | 'fulfilled' | 'error'; export function withRequestStatus() { return signalStoreFeature( withState<{ requestStatus: RequestStatus }>({ requestStatus: 'idle' }), withComputed(({ requestStatus }) => ({ isPending: computed(() => requestStatus() === 'pending'), isFulfilled: computed(() => requestStatus() === 'fulfilled'), isError: computed(() => requestStatus() === 'error'), })) ); } export function setPending(): { requestStatus: RequestStatus } { return { requestStatus: 'pending' }; } export function setFulfilled(): { requestStatus: RequestStatus } { return { requestStatus: 'fulfilled' }; } export function setError(): { requestStatus: RequestStatus } { return { requestStatus: 'error' }; } ``` Questa feature custom può ora essere composta in qualsiasi store che necessita del tracciamento dello stato di caricamento. ```typescript // books-with-status.store.ts import { inject } from '@angular/core'; import { patchState, signalStore, withMethods } from '@ngrx/signals'; import { setAllEntities, withEntities } from '@ngrx/signals/entities'; import { withRequestStatus, setFulfilled, setPending, setError } from './with-request-status'; import { BooksService } from './books.service'; import { Book } from './book.model'; export const BooksStore = signalStore( { providedIn: 'root' }, withEntities(), withRequestStatus(), withMethods((store, booksService = inject(BooksService)) => ({ async loadBooks() { patchState(store, setPending()); try { const books = await booksService.getAll(); patchState(store, setAllEntities(books), setFulfilled()); } catch { patchState(store, setError()); } }, })) ); ``` Lo store composto ora espone i computed signals `isPending()`, `isFulfilled()` e `isError()` senza duplicare la logica. ## Pattern di integrazione nei componenti Signal Store si integra naturalmente con la sintassi dei template Angular attraverso la lettura dei signals. ```typescript // books-list.component.ts import { Component, inject } from '@angular/core'; import { BooksStore } from './books.store'; @Component({ selector: 'app-books-list', standalone: true, template: ` @if (store.isPending()) {
Loading books...
} @if (store.isError()) {
Failed to load books
} @for (book of store.entities(); track book.id) {

{{ book.title }}

{{ book.author }}

}

Total: {{ store.totalBooks() }} books

`, }) export class BooksListComponent { readonly store = inject(BooksStore); constructor() { this.store.loadBooks(); } } ``` Nessuna gestione delle subscription necessaria. Nessun async pipe. I signals si integrano con la [change detection zoneless](/blog/angular/angular-19-zoneless-change-detection-performance) di Angular per prestazioni ottimali. ## Performance e dimensione del bundle L'architettura più leggera di Signal Store si traduce in bundle più piccoli. Il package core `@ngrx/signals` aggiunge circa 4KB gzipped, rispetto ai 15-20KB dello stack NgRx classico completo (`@ngrx/store`, `@ngrx/effects`, `@ngrx/entity`). Signal Store beneficia inoltre della change detection basata sui signals di Angular. I computed signals ricalcolano solo quando le dipendenze cambiano, e i componenti ri-renderizzano solo quando i signals consumati si aggiornano. Questa reattività granulare elimina cicli di change detection non necessari comuni nei pattern basati su Observable. Per applicazioni che [utilizzano già intensivamente RxJS](/blog/angular/rxjs-angular-operators-subjects-signals-interop), i selectors basati su Observable di NgRx classico si integrano perfettamente con le pipeline esistenti. ## Strategia di migrazione da classico a Signal Store Migrare un'applicazione NgRx classica esistente non richiede una riscrittura totale. Entrambe le soluzioni possono coesistere, permettendo un'adozione incrementale. - Iniziare con nuove features usando Signal Store - Migrare i moduli feature isolati uno alla volta - Mantenere features complesse con molti effects su NgRx classico se il costo di migrazione supera i benefici - Utilizzare le utility di [interoperabilità NgRx Signals](https://ngrx.io/guide/signals) per collegare stato basato su Observable e basato su signals > **La coesistenza funziona** > > NgRx Store classico e Signal Store possono funzionare insieme nella stessa applicazione. Il team NgRx supporta ufficialmente entrambi gli approcci e fornisce utility di interoperabilità per collegarli. ## Quando scegliere ciascun approccio ### Scegliere Signal Store quando: - Si sviluppano nuove applicazioni Angular 20+ - Si gestisce stato a livello di feature o componente - La developer experience e la riduzione del boilerplate sono priorità - Il team ha esperienza limitata con NgRx - La dimensione del bundle è importante ### Scegliere NgRx classico quando: - Si mantengono applicazioni NgRx esistenti - Sono richiesti logging rigoroso delle actions e audit trail - Si costruiscono workflow complessi con side effects estesi - È necessario il time-travel debugging completo con Redux DevTools - Il team possiede profonda esperienza NgRx Per i [fondamenti della gestione dello stato](/technologies/angular/interview-questions/state-management-basics), comprendere entrambi gli approcci prepara gli sviluppatori per codebase Angular diverse. ## Conclusione - Signal Store riduce il boilerplate della gestione dello stato del 60-70% rispetto a NgRx classico - NgRx classico rimane la scelta migliore per applicazioni enterprise che richiedono audit trail rigorosi e side effects complessi - Entrambi gli approcci possono coesistere nella stessa applicazione, abilitando una migrazione incrementale - I computed signals di Signal Store forniscono memoizzazione automatica senza definizioni esplicite di selectors - Le custom store features (`signalStoreFeature`) permettono logiche trasversali riutilizzabili - Per nuovi progetti Angular 20+ nel 2026, Signal Store dovrebbe essere la scelta predefinita a meno che requisiti specifici non richiedano NgRx classico --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/it/blog/angular/ngrx-signal-store-vs-classic-ngrx-comparison