0
# Module Configuration
1
2
Module configuration provides NgModule-based setup for traditional Angular applications using the `StoreModule` with `forRoot` and `forFeature` patterns for root and feature state management.
3
4
## Capabilities
5
6
### Store Module
7
8
Main NgModule for configuring NgRx Store in module-based Angular applications.
9
10
```typescript { .api }
11
/**
12
* NgModule for configuring NgRx Store
13
*/
14
class StoreModule {
15
/**
16
* Configure the root store with initial reducers and configuration
17
* @param reducers - Map of reducers or injection token for reducers
18
* @param config - Root store configuration options
19
* @returns ModuleWithProviders for StoreRootModule
20
*/
21
static forRoot<T, V extends Action = Action>(
22
reducers?: ActionReducerMap<T, V> | InjectionToken<ActionReducerMap<T, V>>,
23
config?: RootStoreConfig<T, V>
24
): ModuleWithProviders<StoreRootModule>;
25
26
/**
27
* Configure feature store with feature-specific reducers
28
* @param featureName - Name/key for the feature state slice
29
* @param reducers - Feature reducers map or single reducer
30
* @param config - Feature store configuration options
31
* @returns ModuleWithProviders for StoreFeatureModule
32
*/
33
static forFeature<T, V extends Action = Action>(
34
featureName: string,
35
reducers: ActionReducerMap<T, V> | InjectionToken<ActionReducerMap<T, V>>,
36
config?: StoreConfig<T, V> | InjectionToken<StoreConfig<T, V>>
37
): ModuleWithProviders<StoreFeatureModule>;
38
39
static forFeature<T, V extends Action = Action>(
40
featureName: string,
41
reducer: ActionReducer<T, V> | InjectionToken<ActionReducer<T, V>>,
42
config?: StoreConfig<T, V> | InjectionToken<StoreConfig<T, V>>
43
): ModuleWithProviders<StoreFeatureModule>;
44
45
static forFeature<T, V extends Action = Action>(
46
slice: FeatureSlice<T, V>
47
): ModuleWithProviders<StoreFeatureModule>;
48
}
49
50
/**
51
* Root store module implementation
52
*/
53
class StoreRootModule {}
54
55
/**
56
* Feature store module implementation
57
*/
58
class StoreFeatureModule implements OnDestroy {}
59
```
60
61
**Usage Examples:**
62
63
```typescript
64
import { NgModule } from "@angular/core";
65
import { StoreModule } from "@ngrx/store";
66
import { reducers, metaReducers } from "./app.reducers";
67
68
// Root module configuration
69
@NgModule({
70
imports: [
71
StoreModule.forRoot(reducers, {
72
metaReducers,
73
runtimeChecks: {
74
strictStateImmutability: true,
75
strictActionImmutability: true,
76
strictStateSerializability: true,
77
strictActionSerializability: true,
78
strictActionWithinNgZone: true,
79
strictActionTypeUniqueness: true
80
}
81
})
82
]
83
})
84
export class AppModule {}
85
86
// Feature module with reducer map
87
@NgModule({
88
imports: [
89
StoreModule.forFeature('users', {
90
list: userListReducer,
91
profile: userProfileReducer,
92
preferences: userPreferencesReducer
93
}, {
94
metaReducers: [userMetaReducer],
95
initialState: {
96
list: { entities: [], loading: false },
97
profile: null,
98
preferences: defaultPreferences
99
}
100
})
101
]
102
})
103
export class UserModule {}
104
105
// Feature module with single reducer
106
@NgModule({
107
imports: [
108
StoreModule.forFeature('orders', orderReducer, {
109
initialState: initialOrderState
110
})
111
]
112
})
113
export class OrderModule {}
114
115
// Feature module with FeatureSlice
116
@NgModule({
117
imports: [
118
StoreModule.forFeature({
119
name: 'products',
120
reducer: productReducer,
121
initialState: initialProductState
122
})
123
]
124
})
125
export class ProductModule {}
126
```
127
128
## Configuration Types
129
130
### Root Store Configuration
131
132
```typescript { .api }
133
/**
134
* Configuration options for root store
135
*/
136
interface RootStoreConfig<T, V extends Action = Action> {
137
/** Initial state for the entire application */
138
initialState?: InitialState<T>;
139
/** Meta-reducers applied to all reducers */
140
metaReducers?: MetaReducer<T, V>[];
141
/** Runtime validation checks configuration */
142
runtimeChecks?: Partial<RuntimeChecks>;
143
}
144
145
/**
146
* Runtime validation checks configuration
147
*/
148
interface RuntimeChecks {
149
/** Verifies if the state is serializable */
150
strictStateSerializability: boolean;
151
/** Verifies if the actions are serializable */
152
strictActionSerializability: boolean;
153
/** Verifies that the state isn't mutated */
154
strictStateImmutability: boolean;
155
/** Verifies that actions aren't mutated */
156
strictActionImmutability: boolean;
157
/** Verifies that actions are dispatched within NgZone */
158
strictActionWithinNgZone: boolean;
159
/** Verifies that action types are not registered more than once */
160
strictActionTypeUniqueness?: boolean;
161
}
162
```
163
164
### Feature Store Configuration
165
166
```typescript { .api }
167
/**
168
* Configuration options for feature store
169
*/
170
interface StoreConfig<T, V extends Action = Action> {
171
/** Initial state for the feature */
172
initialState?: InitialState<T>;
173
/** Meta-reducers applied to feature reducers */
174
metaReducers?: MetaReducer<T, V>[];
175
}
176
177
/**
178
* Feature slice configuration
179
*/
180
interface FeatureSlice<T, V extends Action = Action> {
181
/** Name/key for the feature */
182
name: string;
183
/** Reducer function for the feature */
184
reducer: ActionReducer<T, V>;
185
/** Initial state for the feature */
186
initialState?: InitialState<T>;
187
/** Meta-reducers for the feature */
188
metaReducers?: MetaReducer<T, V>[];
189
}
190
191
/**
192
* Initial state configuration type
193
*/
194
type InitialState<T> = Partial<T> | TypeId<Partial<T>> | void;
195
type TypeId<T> = () => T;
196
```
197
198
## Advanced Configuration Patterns
199
200
### Lazy-Loaded Feature Modules
201
202
```typescript
203
// Lazy-loaded feature module
204
@NgModule({
205
imports: [
206
CommonModule,
207
StoreModule.forFeature('billing', billingReducer, {
208
initialState: () => ({
209
// Dynamic initial state
210
invoices: [],
211
currentPlan: getCurrentUserPlan(),
212
settings: getUserBillingSettings()
213
})
214
})
215
]
216
})
217
export class BillingModule {}
218
219
// Route configuration with lazy loading
220
const routes: Routes = [
221
{
222
path: 'billing',
223
loadChildren: () => import('./billing/billing.module').then(m => m.BillingModule)
224
}
225
];
226
```
227
228
### Injectable Configuration
229
230
```typescript
231
import { InjectionToken } from "@angular/core";
232
233
// Injectable reducer configuration
234
export const USER_REDUCERS = new InjectionToken<ActionReducerMap<UserState>>('User Reducers', {
235
factory: () => ({
236
profile: userProfileReducer,
237
settings: userSettingsReducer,
238
notifications: userNotificationsReducer
239
})
240
});
241
242
export const USER_CONFIG = new InjectionToken<StoreConfig<UserState>>('User Config', {
243
factory: () => ({
244
initialState: {
245
profile: null,
246
settings: defaultUserSettings,
247
notifications: { enabled: true, preferences: {} }
248
},
249
metaReducers: environment.production ? [] : [storeFreeze]
250
})
251
});
252
253
// Module using injectable tokens
254
@NgModule({
255
imports: [
256
StoreModule.forFeature('users', USER_REDUCERS, USER_CONFIG)
257
],
258
providers: [
259
// Custom providers if needed
260
{ provide: USER_CONFIG, useFactory: createUserConfig, deps: [UserService] }
261
]
262
})
263
export class UserModule {}
264
```
265
266
### Meta-Reducers Configuration
267
268
```typescript
269
import { MetaReducer } from "@ngrx/store";
270
import { storeFreeze } from "ngrx-store-freeze";
271
import { storeLogger } from "./store-logger";
272
273
// Environment-specific meta-reducers
274
export const metaReducers: MetaReducer<AppState>[] = !environment.production
275
? [storeLogger, storeFreeze]
276
: [];
277
278
// Feature-specific meta-reducers
279
const userMetaReducers: MetaReducer<UserState>[] = [
280
// Audit trail for user actions
281
auditTrailMetaReducer,
282
// Validation for user state changes
283
userValidationMetaReducer
284
];
285
286
@NgModule({
287
imports: [
288
StoreModule.forRoot(reducers, { metaReducers }),
289
StoreModule.forFeature('users', userReducer, {
290
metaReducers: userMetaReducers
291
})
292
]
293
})
294
export class AppModule {}
295
```
296
297
### Multi-Environment Configuration
298
299
```typescript
300
// Environment-specific configurations
301
const developmentConfig: RootStoreConfig<AppState> = {
302
runtimeChecks: {
303
strictStateImmutability: true,
304
strictActionImmutability: true,
305
strictStateSerializability: true,
306
strictActionSerializability: true,
307
strictActionWithinNgZone: true,
308
strictActionTypeUniqueness: true
309
},
310
metaReducers: [storeLogger, storeFreeze]
311
};
312
313
const productionConfig: RootStoreConfig<AppState> = {
314
runtimeChecks: {
315
strictStateImmutability: false,
316
strictActionImmutability: false,
317
strictStateSerializability: false,
318
strictActionSerializability: false,
319
strictActionWithinNgZone: false,
320
strictActionTypeUniqueness: false
321
},
322
metaReducers: []
323
};
324
325
@NgModule({
326
imports: [
327
StoreModule.forRoot(
328
reducers,
329
environment.production ? productionConfig : developmentConfig
330
)
331
]
332
})
333
export class AppModule {}
334
```
335
336
## Module Lifecycle Integration
337
338
### Feature Module Lifecycle
339
340
```typescript
341
import { OnDestroy } from "@angular/core";
342
import { Store } from "@ngrx/store";
343
344
@NgModule({
345
imports: [
346
StoreModule.forFeature('analytics', analyticsReducer)
347
]
348
})
349
export class AnalyticsModule implements OnDestroy {
350
constructor(private store: Store) {
351
// Initialize feature on module load
352
this.store.dispatch(initializeAnalytics());
353
}
354
355
ngOnDestroy() {
356
// Cleanup when module is destroyed
357
this.store.dispatch(cleanupAnalytics());
358
}
359
}
360
```
361
362
### Dynamic Feature Registration
363
364
```typescript
365
import { Injector } from "@angular/core";
366
import { Store } from "@ngrx/store";
367
368
export class DynamicFeatureService {
369
constructor(
370
private store: Store,
371
private injector: Injector
372
) {}
373
374
loadFeature(featureName: string, reducer: ActionReducer<any>) {
375
// Dynamically add feature reducer
376
this.store.addReducer(featureName, reducer);
377
378
// Initialize feature state
379
this.store.dispatch(initializeFeature({ featureName }));
380
}
381
382
unloadFeature(featureName: string) {
383
// Cleanup feature state
384
this.store.dispatch(cleanupFeature({ featureName }));
385
386
// Remove feature reducer
387
this.store.removeReducer(featureName);
388
}
389
}
390
```
391
392
## Integration with Angular Router
393
394
```typescript
395
import { Router } from "@angular/router";
396
import { Store } from "@ngrx/store";
397
398
// Route-based feature loading
399
const routes: Routes = [
400
{
401
path: 'dashboard',
402
loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule),
403
resolve: {
404
// Preload dashboard data
405
dashboardData: (route, state) => {
406
const store = inject(Store);
407
store.dispatch(loadDashboardData());
408
return store.select(selectDashboardLoaded).pipe(
409
filter(loaded => loaded),
410
take(1)
411
);
412
}
413
}
414
}
415
];
416
```
417
418
## Best Practices
419
420
1. **Root Configuration**: Configure runtime checks and meta-reducers at the root level
421
2. **Feature Isolation**: Use separate feature modules for different business domains
422
3. **Lazy Loading**: Combine with Angular's lazy loading for optimal bundle sizes
423
4. **Environment Configuration**: Use different configurations for development and production
424
5. **Injectable Tokens**: Use injection tokens for complex configuration scenarios
425
6. **Meta-Reducers**: Apply feature-specific meta-reducers for targeted functionality