On moving away from Redux (again)

30 November 2025

Picture this, it’s 2016, tech is finally picking back up after the recession. You’re responsible for frontend at the next startup that aspires for the moon. The choice is obvious, a React SPA with Redux for state management. I mean, why wouldn’t you? React has basically taken over after the Angular -> Angular 2 debacle and Redux was created by the same folks. Maybe you’ve just seen Dan’s infamous time travel debugging talk and can’t wait to be able to reproduce bugs with ease.

A decade later, a common thread at every company I’ve worked at recently is trying to move away from Redux. The problem being that as these startups matured and added tonnes of features, over time, their Redux based state management eventually turned to spaghetti. There’s thunks and sagas, multiple levels of nested selectors referenced all over the show with no regard to where the data is coming from, if it’s even available and fresh. Sound familiar?

How it began

When I started my stint at my most recent job, I wasn’t surprised to find an action group dedicated to migrating away from Redux. It was a no brainer for me to join this small group of engineers from different teams, banding together to get rid of Redux.

The problem, however, was that it was incredibly difficult to know how things were connected together. This was caused by us both being relatively new to the company and also not experts in the areas we were attempting to refactor. All of the data fetching and orchestrating was happening through centralised Redux modules (ducks) and then used in several components sprinkled throughout the codebase and even sagas from other modules.

We need a tool

It wasn’t long before I realised that once we knew the places where data was being used, the migration was relatively easy. In most cases, we just needed to replace a selector with a query to fetch the data or serve it up from cache. This would then allow us to simply delete all of the reduxy pieces driving the data (selectors, state, sagas, actions creators, etc).

Given understanding how data was flowing through the app was 80% of the battle, I set out to build a tool that’d help us visualise and make sense of the chaos. The tool takes the name of an action creator (that initiates fetching & making data available through redux) as input and then works out who initiates that action and the downstream effects. These include the saga that handles fetching the data, the slice in redux to which the data is persisted, any selectors and nested selectors that operate over the slice, and finally the consumers of the data, either through the selectors we’ve identified or the slice directly.

It then generates a mermaid diagram to depict how data is flowing through the app, like this:

Example

How it works

The script is fairly scrappy and tailored to the way our redux codebase was organised (ducks with typesafe-actions and sagas for fetching data). It relies on ripgrep to quickly search through the codebase, Babel to generate and traverse ASTs to find important bits within a file (eg, names of selectors that reference a slice), and finally mermaid to draw the flowchart.

When supplied with the name of an async action, it does the following:

  1. First, we find all files that dispatch the request command of the action (these are the initiators)
  2. We then look at reducers that handle the success event of the action to identify redux slices that mutate the store with data from the server
  3. Once we know which bit of the store is updated, we now identify the selectors (recursively to find nested selectors) that use the bit of state being mutated
  4. Finally, we can go through and find all of the consumers that use the selectors

How we used it

Using this tool, we’ve been able to quickly catalogue the redux spaghetti in various product areas of our app. This allowed us to understand, task up, and size the work throughout the app. Now that the effort is known, the work can be picked up either by members of our action group or engineers in the teams that own the product areas when they have some downtime.

You can grab the script here but it’ll likely need to be heavily modified to work with your particular redux setup.