Skip to main content

Getting Started

Persist your NgRx store state to localStorage, sessionStorage, or any custom storage that implements the StateStorage interface. Supports both root and feature states with automatic rehydration on page reload.

Highly inspired by @ngneat/elf-persist-state.

Installation

npm i @ngrx-addons/persist-state

Root State Persistence

import { provideStore } from '@ngrx/store';
import { providePersistStore, localStorageStrategy } from '@ngrx-addons/persist-state';

const counterReducer = ...;
const reducers = { counter: counterReducer } as const;

bootstrapApplication(AppComponent, {
providers: [
provideStore(reducers),
providePersistStore<typeof reducers>({
states: [
{
key: 'counter',
storage: localStorageStrategy,
},
],
}),
],
});

NgModule API

import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { PersistStateModule, localStorageStrategy } from '@ngrx-addons/persist-state';

const counterReducer = ...;
const reducers = { counter: counterReducer } as const;

@NgModule({
imports: [
StoreModule.forRoot(reducers),
PersistStateModule.forRoot<typeof reducers>({
states: [
{
key: 'counter',
storage: localStorageStrategy,
},
],
}),
],
})
export class AppModule {}

Feature State Persistence

import { provideStore, provideState } from '@ngrx/store';
import {
providePersistStore,
providePersistState,
localStorageStrategy,
} from '@ngrx-addons/persist-state';

interface CounterState {
count: number;
}

const counterReducer = ...;

// Root module
bootstrapApplication(AppComponent, {
providers: [
provideStore(),
providePersistStore(),
],
});

// Feature route/module
const counterRoutes: Route[] = [
{
path: 'counter',
providers: [
provideState('counter', counterReducer),
providePersistState<CounterState>({
key: 'counter',
states: [{ storage: localStorageStrategy }],
}),
],
children: [...],
},
];

NgModule API

import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { PersistStateModule, localStorageStrategy } from '@ngrx-addons/persist-state';

interface CounterState {
count: number;
}

const counterReducer = ...;

@NgModule({
imports: [
StoreModule.forRoot(),
PersistStateModule.forRoot(),
],
})
export class AppModule {}

@NgModule({
imports: [
StoreModule.forFeature('counter', counterReducer),
PersistStateModule.forFeature<CounterState>({
key: 'counter',
states: [{ storage: localStorageStrategy }],
}),
],
})
export class CounterModule {}
note

Always call forRoot() / providePersistStore() in your root module, even if you only use feature states.

Rehydration Action

Once state is rehydrated from storage, the rehydrate action (type: @ngrx-addons/persist-state/rehydrate) is dispatched with the restored features. You can use it in effects or meta-reducers:

import { rehydrate } from '@ngrx-addons/persist-state';

// In an effect
this.actions$.pipe(
ofType(rehydrate),
tap(({ features }) => console.log('Rehydrated:', features)),
);