Introduction
As your Angular application grows, managing shared state between components becomes increasingly complex. NGXS (pronounced "nexus") offers a simple, intuitive, and powerful state management pattern for Angular apps, based on the principles of Redux but with a more Angular-friendly approach.
In this article, we’ll explore how to set up and use NGXS to manage application state efficiently.
Why NGXS?
NGXS provides:
- A simple API using decorators and observables.
- Type-safe state and actions.
- Built-in support for plugins (logger, devtools, storage).
- Easy-to-understand state mutation via actions.
Step 1. Install NGXS
Use the Angular CLI to install the NGXS packages:
npm install @ngxs/store --save
Optional DevTools and plugins:
npm install @ngxs/devtools-plugin @ngxs/logger-plugin --save
Step 2. Create a State Model
Create an interface to define your state:
// models/todo.model.ts
export interface Todo {
id: number;
title: string;
completed: boolean;
}
Step 3. Define Actions
Actions are plain classes that represent events in your app.
// actions/todo.actions.ts
export class AddTodo {
static readonly type = '[TODO] Add';
constructor(public payload: string) {}
}
export class ToggleTodo {
static readonly type = '[TODO] Toggle';
constructor(public id: number) {}
}
Step 4. Create the State
Define the NGXS state using the @State() decorator.
// state/todo.state.ts
import { State, Action, StateContext, Selector } from '@ngxs/store';
import { AddTodo, ToggleTodo } from '../actions/todo.actions';
import { Todo } from '../models/todo.model';
@State<Todo[]>({
name: 'todos',
defaults: []
})
export class TodoState {
@Selector()
static getTodos(state: Todo[]) {
return state;
}
@Action(AddTodo)
add({ getState, patchState }: StateContext<Todo[]>, { payload }: AddTodo) {
const state = getState();
const newTodo: Todo = { id: Date.now(), title: payload, completed: false };
patchState([...state, newTodo]);
}
@Action(ToggleTodo)
toggle({ getState, patchState }: StateContext<Todo[]>, { id }: ToggleTodo) {
const state = getState();
const updated = state.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
);
patchState(updated);
}
}
Step 5. Register the State in the App Module
// app.module.ts
import { NgxsModule } from '@ngxs/store';
import { TodoState } from './state/todo.state';
@NgModule({
declarations: [...],
imports: [
NgxsModule.forRoot([TodoState]),
],
bootstrap: [...]
})
export class AppModule {}
Step 6. Use the State in Components
// app.component.ts
import { Store, Select } from '@ngxs/store';
import { Observable } from 'rxjs';
import { TodoState } from './state/todo.state';
import { AddTodo, ToggleTodo } from './actions/todo.actions';
@Component({...})
export class AppComponent {
@Select(TodoState.getTodos) todos$: Observable<Todo[]>;
constructor(private store: Store) {}
addTodo(title: string) {
this.store.dispatch(new AddTodo(title));
}
toggleTodo(id: number) {
this.store.dispatch(new ToggleTodo(id));
}
}
Conclusion
NGXS brings a clean and declarative way to manage state in Angular apps. With actions, selectors, and plugins, it streamlines complex state flows into something more maintainable and scalable.
Happy coding !!

Join the conversation! Your thoughts help the community grow.