Next, let's talk about plugins. Similar to Redux's meta reducers, we have a plugin interface that allows you to build a global plugin for your state.

All you have to do is call withNgxsPlugin with a plugin class. If your plugins have options associated with them, we also suggest defining an injection token.

Let's take a look at a basic example of a logger:

import { makeEnvironmentProviders, InjectionToken, Injectable, Inject } from '@angular/core';
import { withNgxsPlugin } from '@ngxs/store';
import { NgxsPlugin } from '@ngxs/store/plugins';


export class LoggerPlugin implements NgxsPlugin {
  constructor(@Inject(NGXS_LOGGER_PLUGIN_OPTIONS) private options: any) {}

  handle(state, action, next) {
    console.log('Action started!', state);
    return next(state, action).pipe(
      tap(result => {
        console.log('Action happened!', result);

export function withNgxsLoggerPlugin(options?: any) {
  return makeEnvironmentProviders([
      useValue: options

You can also use pure functions for plugins. The above example in a pure function would look like this:

export function logPlugin(state, action, next) {
  console.log('Action started!', state);
  return next(state, action).pipe(tap(result) => {
    console.log('Action happened!', result);

NOTE: When providing a pure function make sure to use useValue instead of useClass.

To register a plugin with NGXS, add the plugin to your provideStore as an NGXS feature and optionally pass in the plugin options like this:

export const appConfig: ApplicationConfig = {
  providers: [provideStore([ZooState], withNgxsLoggerPlugin({}))]

Last updated