# NgRx Signal Store vs NgRx Clásico en 2026: ¿Cuál Elegir? > Comparación detallada entre NgRx Signal Store y NgRx clásico para la gestión de estado en Angular 2026. Conoce las diferencias arquitectónicas, ejemplos de código y consejos para elegir la solución correcta. - Published: 2026-07-11 - Updated: 2026-07-11 - Author: SharpSkill - Reading time: 5 min --- NgRx Signal Store representa un cambio fundamental en la gestión de estado de Angular, reemplazando el patrón tradicional inspirado en Redux (actions-reducers-selectors) por un enfoque reactivo basado en signals. Esta comparación examina ambas soluciones para ayudar a los desarrolladores Angular a tomar decisiones arquitectónicas informadas en 2026. > **Guía de Decisión Rápida** > > Usar **Signal Store** para estado a nivel de funcionalidad y aplicaciones de complejidad media donde la reducción de boilerplate importa. Usar **NgRx Clásico** para aplicaciones empresariales que requieren pistas de auditoría estrictas, efectos secundarios complejos y depuración extensiva con DevTools. ## Entendiendo las Diferencias Arquitectónicas NgRx clásico sigue el [patrón Redux](https://redux.js.org/understanding/thinking-in-redux/three-principles): las acciones describen eventos, los reducers producen nuevo estado inmutable, y los selectors extraen datos. Cada cambio de estado fluye a través de un pipeline predecible y rastreable. Signal Store adopta un enfoque diferente. En lugar de despachar acciones a través de reducers, el estado vive en signals reactivos. Las actualizaciones ocurren mediante métodos que llaman a `patchState()`, y los valores derivados provienen de signals computados en lugar de selectors memorizados. | Aspecto | NgRx Clásico | Signal Store | |---------|--------------|---------------| | Modelo Mental | Redux/Flux | Servicios Reactivos | | Boilerplate | Alto (actions, reducers, selectors, effects) | Bajo (state, methods, computed) | | Reactividad | Observables RxJS | Signals Angular | | DevTools | Redux DevTools completo | Signal Store DevTools (vía plugin) | | Curva de aprendizaje | Pronunciada | Moderada | | Tamaño del Bundle | Mayor | Menor | Para desarrolladores ya familiarizados con los [Signals de Angular](/technologies/angular/interview-questions/angular-signals), Signal Store se siente como una extensión natural de las primitivas reactivas del framework. ## NgRx Clásico: El Patrón Redux en Angular NgRx clásico organiza la gestión de estado alrededor de actions, reducers, selectors y effects. Esta separación impone predictibilidad a costa de verbosidad. ```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 }>(), }, }); ``` La API `createActionGroup` agrupa acciones relacionadas bajo una sola fuente, mejorando la legibilidad en DevTools y reduciendo el boilerplate comparado con llamadas individuales a `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, })) ); ``` Los reducers siguen siendo funciones puras que retornan nuevos objetos de estado. La función `on()` maneja la coincidencia de acciones y las actualizaciones de estado de forma concisa. ```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) ); ``` Los selectors proporcionan memorización automáticamente. El selector `selectPublishedBooks` solo recalcula cuando el array de libros cambia, haciendo las lecturas eficientes incluso en stores actualizados frecuentemente. ## NgRx Signal Store: Gestión de Estado Signals-First Signal Store consolida estado, valores computados y métodos en un único servicio inyectable. La [documentación oficial de NgRx](https://ngrx.io/guide/signals/signal-store) lo describe como una "solución de gestión de estado completamente equipada con soporte nativo para Signals de Angular." ```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), })); }, })) ); ``` Toda la gestión de estado de una funcionalidad cabe en un solo archivo. Las propiedades de estado se convierten en signals automáticamente, los signals computados reemplazan a los selectors, y los métodos reemplazan los despachos de acciones. ## Gestión de Entidades con withEntities Ambos enfoques soportan colecciones de entidades, pero la funcionalidad `withEntities` de Signal Store reduce drásticamente el código. ```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 funcionalidad `withEntities` proporciona automáticamente los signals `ids`, `entityMap` y `entities`. Los actualizadores de entidades como `addEntity`, `removeEntity` y `updateEntity` manejan las mutaciones de colecciones. ## Features de Store Personalizados para Reusabilidad La función `signalStoreFeature` de Signal Store permite extraer y reutilizar preocupaciones transversales a través de los stores. ```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' }; } ``` Este feature personalizado ahora puede componerse en cualquier store que necesite seguimiento del estado de carga. ```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()); } }, })) ); ``` El store compuesto ahora expone los signals computados `isPending()`, `isFulfilled()` e `isError()` sin duplicar lógica. ## Patrones de Integración en Componentes Signal Store se integra naturalmente con la sintaxis de templates de Angular mediante lecturas de 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()) {
Cargando libros...
} @if (store.isError()) {
Error al cargar los libros
} @for (book of store.entities(); track book.id) {

{{ book.title }}

{{ book.author }}

}

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

`, }) export class BooksListComponent { readonly store = inject(BooksStore); constructor() { this.store.loadBooks(); } } ``` Sin gestión de suscripciones. Sin pipes async. Los signals se integran con la [detección de cambios zoneless](/blog/angular/angular-19-zoneless-change-detection-performance) de Angular para un rendimiento óptimo. ## Consideraciones de Rendimiento y Tamaño de Bundle La arquitectura más ligera de Signal Store se traduce en bundles más pequeños. El paquete core `@ngrx/signals` añade aproximadamente 4KB comprimido con gzip, comparado con 15-20KB para el stack completo de NgRx clásico (`@ngrx/store`, `@ngrx/effects`, `@ngrx/entity`). Signal Store también se beneficia de la detección de cambios basada en signals de Angular. Los signals computados solo recalculan cuando las dependencias cambian, y los componentes solo se re-renderizan cuando los signals consumidos se actualizan. Esta reactividad granular elimina ciclos innecesarios de detección de cambios comunes en patrones basados en Observables. Para aplicaciones que ya usan [RxJS extensivamente](/blog/angular/rxjs-angular-operators-subjects-signals-interop), los selectors basados en Observables de NgRx clásico se integran perfectamente con pipelines existentes. ## Estrategia de Migración de Clásico a Signal Store Migrar una aplicación NgRx clásica existente no requiere una reescritura completa. Ambas soluciones pueden coexistir, permitiendo adopción incremental. - Comenzar con nuevas funcionalidades usando Signal Store - Migrar módulos de funcionalidades aislados uno a la vez - Mantener funcionalidades complejas con muchos effects en NgRx clásico si el costo de migración excede el beneficio - Usar las utilidades de [interoperabilidad de NgRx Signals](https://ngrx.io/guide/signals) para conectar estado basado en Observables y basado en signals > **La Coexistencia Funciona** > > NgRx Store clásico y Signal Store pueden ejecutarse lado a lado en la misma aplicación. El equipo de NgRx soporta oficialmente ambos enfoques y proporciona utilidades de interoperabilidad para conectarlos. ## Cuándo Elegir Cada Enfoque ### Elegir Signal Store cuando: - Se construyen nuevas aplicaciones Angular 20+ - Se gestiona estado a nivel de funcionalidad o componente - La experiencia del desarrollador y reducción de boilerplate son prioridad - El equipo tiene experiencia limitada con NgRx - El tamaño del bundle importa ### Elegir NgRx Clásico cuando: - Se mantienen aplicaciones NgRx existentes - Se requieren pistas de auditoría estrictas con logging de acciones - Se construyen flujos de trabajo complejos con efectos secundarios extensivos - Se necesita depuración time-travel completa de Redux DevTools - El equipo tiene experiencia profunda en NgRx Para los [fundamentos de gestión de estado](/technologies/angular/interview-questions/state-management-basics), entender ambos enfoques prepara a los desarrolladores para diversos codebases de Angular. ## Conclusión - Signal Store reduce el boilerplate de gestión de estado entre 60-70% comparado con NgRx clásico - NgRx clásico sigue siendo la mejor opción para aplicaciones empresariales que requieren pistas de auditoría estrictas y efectos secundarios complejos - Ambos enfoques pueden coexistir en la misma aplicación, permitiendo migración incremental - Los signals computados de Signal Store proporcionan memorización automática sin definiciones explícitas de selectors - Los features de store personalizados (`signalStoreFeature`) permiten preocupaciones transversales reutilizables - Para nuevos proyectos Angular 20+ en 2026, Signal Store debería ser la elección por defecto a menos que requisitos específicos demanden NgRx clásico --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/es/blog/angular/ngrx-signal-store-vs-classic-ngrx-comparison