How to design Redux apps for scalability and type-safety

Share on facebook
Share on google
Share on twitter
Share on linkedin

Previously I have written about three ways to use Redux, but how do you structure your Redux app for a scalable application?

Redux is good for state management in big applications because you get to decouple write from read and you are not dependent on passing data through (potentially) many levels of components. But structured the wrong way you will end up in a maintenance hell.

In this post, we will look at how to structure a Redux app for scalability, easy maintenance, and type-safety. The code is based on implementing these Redux best practices for an Angular TodoApp which can be found on my Github.

Put Redux code in the corresponding folder

In the Angular style guide, it is recommended to put the code in feature modules. In the same manner, you want to place your Redux code where it is used, for higher cohesion. I call this folder “Redux-API” and this folder should contain action, reducer, selector, state and epic for the corresponding feature.

State Class

The state class contains the state of a part of the application. Often you see this as an interface called “app state”, but I prefer to use a class so that the constructor can be used for setting the initial state.

Type-safe Actions

Actions are dispatching events which are handled by reducers or epics. As I explained in my post about three ways to use Redux I recommended using actions for dispatching events and not commands.

Generic Action class

The generic action class is a generic class used to specify an action with a generic type and payload property as these properties follow the Redux standards.

ActionTypes as enums

Even though action types are a string, they should provide a type-safe way for selecting the action type. This is done with string enums which can look like this:

Complete action code

A complete example of an action with the above guidelines is:

Type-safe Reducers

Reducers are pure functions that take in the previous state and an action and returns a new state. Many Redux apps enforce immutability by using eg. ImmutableJS for ensuring that only actions can change the state.

Reducers are split into multiple reducer functions, that easy take the previous state and an action and returns a new state.

The reducer class looks like this:

Selector classes for reusable and type-safe store selection

One of the biggest disadvantages with reactive apps is that the control flow of the app can be very confusing, meaning it can be very hard to grasp the consequences of dispatching an action because you don’t know where the application is subscribing to different parts of the Redux store.

Selector classes mitigate this problem by creating reusable selector classes. The makes it easier for other classes to reference a part of the application because they just need to inject the selector for the given app state part and it makes it easy to search for all the places in the application a specific part of the Redux store is subscribed to.


Epics are triggered with an action, just as reducers, but dispatches other actions and is used for eg, doing HTTP requests, where you want to update the loading and error state continuously as the HTTP request is performed. Epics are often used when an action is dispatched as a Command, which, as I have written about previously, is not something I recommend as it complicates control flow and services can often do the same a lot easier.

This is what an epic, that is dispatching 10 actions around in the application, feels like maintaining:

Wrapping up

In this post, we saw how to make your Redux applications more stable and maintainable by ensuring cohesion of the Redux code to where it belongs in the application as well as creating type-safety by statically type actions and reducers. Selecting values from the Redux store with selector classes is easier and more maintainable as the selector can be injected into the code and provide type-safe selections of the Redux Store.

Do you want to become an Angular architect? Check out Angular Architect Accelerator.

Related Posts and Comments

How to Set up a CI pipeline with Azure Pipelines and Nx

It goes without saying that having a CI pipeline for your Angular apps is a must. Setting one up for regular Angular apps is fairly straightforward but when you have an Nx monorepo there are certain other challenges that you have to overcome to successfully orchestrate a “build once, deploy many” pipeline. This post will

Read More »

How to Set Up Git Hooks in an Nx Repo

Git hooks can be used to automate tasks in your development workflow. The earlier a bug is discovered, the cheaper it is to fix (and the less impact it has). Therefore it can be helpful to run tasks such as linting, formatting, and tests when you are e.g. committing and pushing your code, so any

Read More »

The Stages of an Angular Architecture with Nx

Long gone are the times when the frontend was just a dumb static website. Frontend apps have gotten increasingly complex since the rise of single-page application frameworks like Angular. It comes with the price of increased complexity and the ever-changing frontend landscape requires you to have an architecture that allows you to scale and adapt

Read More »

The Best Way to Use Signals in Angular Apps

Since Angular 16, Angular now has experimental support for signals and there is a lot of confusion in the community about whether this is going to replace RxJS or how it should be used in an app in combination with RxJS. This blog post sheds some light on what I think is the best way

Read More »

High ROI Testing with Cypress Component Testing

Testing is one of the most struggled topics in Angular development and many developers are either giving up testing altogether or applying inefficient testing practices consuming all their precious time while giving few results in return. This blog post will change all this as we will cover how I overcame these struggles the hard way

Read More »