---
title: "Angular State Management with NgRx"
published_at: "2022-04-13T12:55:27+00:00"
modified_at: "2026-08-17T10:24:56+00:00"
url: "https://www.syncfusion.com/blogs/post/angular-state-management-ngrx"
excerpt: "Learn how to manage complex Angular state using NgRx. Understand core concepts, implementation steps, comparisons, and best practices for scalable apps."
taxonomy_category:
  - "Angular"
  - "Development"
  - "Web"
taxonomy_post_tag:
  - "Angular"
  - "development"
  - "state management support"
  - "Web"
---

# Angular State Management with NgRx

[Chameera Dulanga](https://www.syncfusion.com/blogs/author/chameera-dulanga)

![Angular State Management with NgRx](https://www.syncfusion.com/blogs/wp-content/uploads/2022/04/596-x-334@2x-compressed.jpg)


**TL;DR:** NgRx is Angular’s Redux‑inspired state management library that centralizes application state into a single immutable store. It’s ideal for large or complex Angular apps that need predictable data flow, easier debugging, and long‑term scalability. This guide explains core concepts, implementation steps, trade‑offs, and best practices so you can confidently decide whether NgRx is the right choice.

Taming the ever-growing complexity of UI state in [Angular](https://www.syncfusion.com/angular-ui-components)
 applications often feels like wrestling with wild vines, slowing development and turning debugging into a maze. NgRx, Angular’s Redux-inspired state library, brings order with a single immutable store, explicit action dispatching, and pure reducers that enforce a clean, unidirectional data flow. You’ll learn how to define strongly‑typed actions, compose reducers, and craft selectors to derive precise slices of state, then wire everything up in your AppModule and components.

We’ll even cover handling real-world side effects using NgRx Effects, so you can orchestrate asynchronous tasks without scattering service calls across your components. By the end, you’ll have a scalable blueprint for managing blog articles (or any domain data) with predictable updates, easier testing, and optimized performance, no more tangled service calls or brittle component logic slowing you down.

## What is NgRx?

![NgRx Website](https://www.syncfusion.com/blogs/wp-content/uploads/2022/04/NgRx-Website.png)

NgRx Website

NgRx is inspired by Redux and helps developers simplify the application’s state in objects by enforcing a unidirectional data flow.


## How NgRx works

![NgRx state management process](https://www.syncfusion.com/blogs/wp-content/uploads/2022/04/NgRx-state-management-process.jpg)The NgRx state management process is a combination of five key elements:

- **Store**: The application state is maintained in the store. It is immutable.
- **Selectors**: Angular components can subscribe to the store and get updates through selectors.
- **Reducers**: Reducers are responsible for handling the transition from one state to another.
- **Actions**: Actions modify the state of the store by using reducers.
- **Effects**: Effects are the results of actions. Also, they can be used to listen for particular action types and run when the action happens.

Although this process seems complex to implement, it is useful for data communication when the application grows.

So, let’s see how we can use NgRx in an Angular application.

## How to use NgRx store with Angular

In this tutorial, we will be implementing a simple application to manage blog articles using NgRx store and Angular.

### Step 1: Installing NgRx

[NgRx](https://ngrx.io/)
 can be installed using NPM, Yarn, or Angular CLI as follows:

```
// NPM
npm install @ngrx/store --save

// Yarn
yarn add @ngrx/store

// Angular CLI
ng add @ngrx/store@latest
```


### Step 2: Creating the Store

After installation, you need to create a separate directory named **/store** under the ** src/app** directory. This folder will contain all the files related to the NgRx store. The folder structure of the store directory would look like this:

```
-- app-- src-- app-- store
-- models-- actions
-- reducers
```

As a first step, you need to create an interface for articles. Let’s name the model **article.model.ts**.

```
export interface Article {
  id: string;
  name: string;
  author: string;
  publisher: string;
}
```

Then, you need to create an action file to define NgRx actions. Here, we have created a file named **articles.actions.ts** under the ** actions** folder and imported ** createAction** from the NgRx store.

```
import { createAction, props } from '@ngrx/store';
import { Article } from '../models/article.model';

export const addArticle = createAction(
  '[ARTICLE] Add ARTICLE',
  props<{ article: Article }>()
);
```

In the above file, we define a new action using the **createAction** function from NgRx. This method is preferred over the class-based approach, providing a more concise and scalable way to manage actions. The ** addArticle** action has a type (‘[ARTICLE] Add ARTICLE’) and uses props to specify an article as its payload.

Now, we need to create a reducer to help us in state transitions. So, inside the reducers directory, create an **article.reducer.ts** file with the following content:

```
import { createReducer, on } from '@ngrx/store';
import { addArticle } from '../actions/article.actions';
import { Article } from '../models/article.model';

export const initialState: ReadonlyArray<Article> = [
  {
    id: '1',
    title: 'Angular State Management with NgRx',
    author: 'Chameera Dulanga',
    publisher: 'SyncFusion',
  },
];

export const articleReducer = createReducer(
  initialState,
  on(addArticle, (state, { article }) => [...state, article])
);
```

In the above reducer, we have created an initialState to represent the initial collection of articles. This state is a read-only array of Article objects. The **articleReducer** function is then created using createReducer. It defines how the state should change in response to actions. Here, ** on(addArticle, …)** listens for the ** addArticle** action and adds the new article to the state array. If no matching action is dispatched, it simply returns the current state unaltered.

For the final step of store creation, we need to create another model to keep all application states in a single place. Here, we have named it **state.model.ts** and it will look like this:

```
import { Article } from '../models/article.model';

export interface State {
  readonly article: Array<Article>;
}
```

### Step 3: Registering the NgRx store

Now, you need to register the NgRx store in the Angular application. To do this, import the **articleReducer** you’ve created and include it in the providers array of the ** appConfig** object within the ** app.config.ts** file.

```
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideStore } from '@ngrx/store';
import { routes } from './app.routes';
import { ReactiveFormsModule } from '@angular/forms';
import { importProvidersFrom } from '@angular/core';
import { articleReducer } from './store/reducers/article.reducer';

export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes),
    provideStore({ article: articleReducer }),
    importProvidersFrom(ReactiveFormsModule)
  ]
};
```


### Step 4: Using the NgRx store

After registering the store in **appConfig**, you can start using it in your components. Here, we will be using the ** AppComponent** to display and add articles to the store.

```
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { Store, select } from '@ngrx/store';
import { Observable } from 'rxjs';
import { Article } from './store/models/article.model';
import { State } from './store/models/state.model';
import { addArticle } from './store/actions/article.actions';
import { CommonModule } from '@angular/common';

@Component({
  selector:    'app-root',
  standalone:  true,
  imports:     [ReactiveFormsModule, CommonModule],
  templateUrl: './app.component.html',
  styleUrls:   ['./app.component.css'],
})
export class AppComponent implements OnInit {
  articles$!: Observable<Array<Article>>;
  articleForm!: FormGroup;

  constructor(
    private store: Store<State>,
    private fb: FormBuilder
  ) {}

  ngOnInit(): void {
    this.articles$ = this.store.pipe(select(state => state.article));
    this.articleForm = this.fb.group({
      id: ['', Validators.required],
      title: [''],
      author: [''],
      publisher: [''],
    });
  }

  addArticle() {
    if (this.articleForm.valid) {
      this.store.dispatch(addArticle({ article: this.articleForm.value }));
      this.articleForm.reset();
    }
  }
}
```

The above code shows the **app.component.ts** file of our example. There, we have set ** articles$** to a type of observable and subscribed to the store to get the articles. The ** addArticle()** function is responsible for dispatching new articles to the store.

Now, we need to modify the **app.component.html** file to display and create articles.

```
<section>
  <div class="container">
    <div class="row" style="margin-top: 5%;">

      <div class="col-md-12" style="text-align: center; margin: 5%;">
        <h2>My Articles</h2>
      </div>

      <div class="col-md-6">
        <div class="card p-4 shadow-sm">
          <form[formGroup]="articleForm" (ngSubmit)="addArticle()">

            <div class="form-group">
              <label for="id">Article Id</label>
              <input
                type="text"
                class="form-control"
                formControlName="id"
                id="id"
                required
              />
            </div>

            <div class="form-group">
              <label for="title">Title</label>
              <input
                type="text"
                class="form-control"
                formControlName="title"
                id="title"
              />
            </div>

            <div class="form-group">
              <label for="author">Author</label>
              <input
                type="text"
                class="form-control"
                formControlName="author"
                id="author"
              />
            </div>

            <div class="form-group">
              <label for="publisher">Publisher</label>
              <input
                type="text"
                class="form-control"
                formControlName="publisher"
                id="publisher"
              />
            </div>

            <button type="submit" class="btn btn-primary">Submit</button>

          </form>
        </div>
      </div>

      <div class="col-md-6">
        <ul class="list-group">
          <li class="list-group-item list-group-item-primary"
            *ngFor="let article of articles$ | async">
            {{article.title}} by <b>{{article.author}}</b>
          </li>
        </ul>
      </div>

    </div>
  </div>
</section>
```

![Screenshot of the application demonstrating NgRX](https://www.syncfusion.com/blogs/wp-content/uploads/2022/04/Screenshot-of-the-application-demonstrating-NgRX.png)  
 That’s all there is to it! We have successfully configured an NgRx store with an Angular application.

## GitHub reference

For more details, you can find the [Angular State Management with NgRx demo on GitHub](https://github.com/SyncfusionExamples/angular-state-management-with-ngrx)
.

## Frequently Asked Questions

Is NgRx necessary for every Angular app?No. NgRx is best suited for applications with complex, shared, or highly interactive state requirements.

Is NgRx difficult to learn?There is a learning curve, especially for teams new to Redux patterns, but it improves long-term maintainability.

Can I mix NgRx with services?Yes. Services are commonly used within NgRx Effects to handle API calls and side effects.

How does NgRx improve debugging?NgRx DevTools enable time-travel debugging and make it easy to inspect every state change.

Does NgRx affect performance?When used correctly, NgRx can improve performance through memoized selectors and controlled state updates.


## Conclusion

Thanks for reading! We’ve just walked through building an Angular application using [NgRx](https://ngrx.io/)
 for predictable and scalable state management. More importantly, we’ve learned architectural principles that extend beyond this single app.

### What makes this approach powerful

We’ve implemented a blueprint for managing complex state in Angular:

- **Unidirectional data flow** for predictable updates and easier debugging.
- **Strongly typed actions and reducers** for type safety and maintainability.
- **Selectors for optimized state access** without redundant computations.
- **Effect-based side effects** to handle asynchronous tasks cleanly.
- **Modular architecture** that scales with enterprise-level applications.

These patterns apply whether you’re building dashboards, e-commerce platforms, or data-driven apps. The principles remain the same: **type safety, reactive state, error resilience, and clean separation of concerns.**

We now have a foundation for creating Angular applications that are maintainable, testable, and optimized for performance.

Syncfusion’s [Angular](https://www.syncfusion.com/angular-components)
 component library offers over 145 high-performance, lightweight, and responsive UI components, including data grids, charts, calendars, and editors. These components integrate seamlessly with NgRx, making it easier to build enterprise-ready apps with rich, interactive UIs.

If you’re a Syncfusion user, you can download the setup from the [license and downloads](https://www.syncfusion.com/account/downloads)
 page. Otherwise, you can download a free [30-day trial](https://www.syncfusion.com/downloads/)
.

You can also contact us through our [support forum](https://www.syncfusion.com/forums)
, [support portal](https://support.syncfusion.com/)
, or [feedback portal](https://www.syncfusion.com/feedback/)
 for queries. We are always happy to assist you!

## Related Blogs



[How to Build an AI-Powered Writing Assistant in Angular Using Google Gemini API (Part 2)](https://www.syncfusion.com/blogs/post/ai-writing-assistant-angular-gemini-2)



[How to Build an AI-Powered Writing Assistant in Angular Using Google Gemini API (Part 1)](https://www.syncfusion.com/blogs/post/ai-writing-assistant-angular-gemini)



[How to Build UML Sequence Diagrams in Angular with Mermaid Syntax](https://www.syncfusion.com/blogs/post/angular-uml-sequence-diagram)



[Build Faster with Syncfusion AI Coding Assistant Tools: Agent Skills and MCP Servers](https://www.syncfusion.com/blogs/post/ai-coding-assistant-agent-skills-mcp)
