redux vs zustand vs jotai vs mobx vs recoil
State Management Libraries Comparison
3 Years
reduxzustandjotaimobxrecoilSimilar Packages:
What's State Management Libraries?

State management libraries in JavaScript help manage and centralize the state of an application, making it easier to share data between components, handle complex state logic, and maintain a predictable state across the app. These libraries provide tools and patterns for managing state efficiently, improving code organization, and enhancing the scalability of applications. They are particularly useful in large applications where state needs to be shared across multiple components or where state changes need to be tracked and managed in a structured way. Popular state management libraries include Redux, MobX, Recoil, Zustand, and Jotai, each offering unique approaches and features for handling state in React and other JavaScript frameworks.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
redux14,621,852
61,312290 kB442 years agoMIT
zustand10,422,070
54,29692.4 kB55 days agoMIT
jotai1,956,110
20,411487 kB813 days agoMIT
mobx1,955,528
28,0144.33 MB735 months agoMIT
recoil534,988
19,5932.21 MB3232 years agoMIT
Feature Comparison: redux vs zustand vs jotai vs mobx vs recoil

State Management Approach

  • redux:

    redux follows a unidirectional data flow model with a single source of truth (the store). State is updated through actions and reducers, which ensures that state changes are predictable and traceable. This approach is particularly useful for large applications where maintaining a clear and consistent state is crucial.

  • zustand:

    zustand takes a more straightforward approach to state management by using hooks to create a global store. It allows for both local and global state management without the need for a complex setup. This makes it easy to use and understand, especially for smaller applications or teams looking for a simple solution.

  • jotai:

    jotai uses atomic state management, where each piece of state is managed independently. This allows for fine-grained updates, meaning only the components that depend on a specific atom will re-render when that atom's state changes. This approach minimizes unnecessary re-renders and improves performance, especially in large applications.

  • mobx:

    mobx employs a reactive programming model, where state is stored in observable objects. When the state changes, any components or functions that observe that state automatically update. This creates a more dynamic and intuitive way to manage state, as changes are reflected in the UI automatically without needing to manually trigger updates.

  • recoil:

    recoil introduces a more React-centric approach to state management by using atoms (units of state) and selectors (functions that derive state). Atoms are similar to jotai's atoms, but Recoil also allows for derived state through selectors, which can compute values based on one or more atoms. This allows for more complex state relationships while still keeping the API simple and intuitive.

Boilerplate Code

  • redux:

    redux is known for its boilerplate, as it requires defining actions, reducers, and the store. This can lead to a lot of repetitive code, especially in large applications. However, many developers appreciate the structure and predictability that Redux provides, which can make the initial investment in boilerplate worth it for complex projects.

  • zustand:

    zustand has very little boilerplate. You create a store using a simple function and access the state directly in your components. There are no actions or reducers to define, which makes it quick and easy to set up.

  • jotai:

    jotai has minimal boilerplate, especially compared to Redux. You define atoms (units of state) and use them directly in your components. There are no reducers, actions, or complex setup required, making it quick to implement and easy to understand.

  • mobx:

    mobx also minimizes boilerplate by allowing you to define observable state directly in your components or stores. The reactive nature of MobX means you don’t need to write additional code to handle state updates; the library takes care of it for you.

  • recoil:

    recoil requires some setup to define atoms and selectors, but it is still relatively low compared to Redux. The API is designed to be intuitive, and once you understand the concept of atoms and selectors, it’s easy to manage state with minimal code.

Performance

  • redux:

    redux performance can be impacted by how state updates are handled. Since state is updated in a single store, all components that depend on that state will re-render when it changes. This can be mitigated by using techniques like memoization and shouldComponentUpdate, but it requires additional effort to optimize performance.

  • zustand:

    zustand is lightweight and performs well, especially for small to medium-sized applications. Its simple design means that state updates are quick and efficient, with minimal overhead. However, like any state management solution, performance can be affected by how the state is structured and accessed.

  • jotai:

    jotai is designed for performance, especially with its atomic state model. Since only the components that use a specific atom re-render when that atom’s state changes, it minimizes unnecessary renders and keeps the UI responsive. This is particularly beneficial in large applications where state changes are frequent.

  • mobx:

    mobx is also highly performant due to its reactive nature. It tracks which components depend on which pieces of state and only re-renders those components when the relevant state changes. This fine-grained reactivity can lead to significant performance improvements, especially in applications with complex state relationships.

  • recoil:

    recoil offers good performance, but it can vary depending on how atoms and selectors are used. Since atoms are updated independently, re-renders are limited to components that use the updated atom. However, poorly designed selectors can lead to unnecessary re-renders, so it’s important to use them judiciously.

Community and Ecosystem

  • redux:

    redux has one of the largest communities in the state management ecosystem. It is well-established, with a vast ecosystem of middleware, tools, and libraries. The documentation is extensive, and there are countless tutorials and resources available for developers of all skill levels.

  • zustand:

    zustand is gaining popularity for its simplicity and minimalism. It has an active community and is well-documented, but it is smaller compared to more established libraries like Redux and MobX. As it grows, more resources and third-party integrations are likely to emerge.

  • jotai:

    jotai is a relatively new library but has quickly gained popularity and has an active community. Its simplicity and modern approach to state management have attracted many developers, and it is well-documented, making it easy to learn and use.

  • mobx:

    mobx has a large and established community with a wealth of resources, tutorials, and third-party libraries. It is a mature library that has been around for many years, and its reactive programming model is well-understood and widely adopted.

  • recoil:

    recoil is developed by Facebook and has a growing community. It is still relatively new, but it has strong backing and is actively maintained. The documentation is comprehensive, and there are many resources available for learning and using Recoil effectively.

Ease of Use: Code Examples

  • redux:

    State management with redux

    import { createStore } from 'redux';
    import { Provider, useSelector, useDispatch } from 'react-redux';
    
    // Define initial state
    const initialState = { count: 0 };
    
    // Define a reducer
    const counterReducer = (state = initialState, action) => {
      switch (action.type) {
        case 'INCREMENT':
          return { ...state, count: state.count + 1 };
        default:
          return state;
      }
    };
    
    // Create a Redux store
    const store = createStore(counterReducer);
    
    function Counter() {
      const count = useSelector((state) => state.count);
      const dispatch = useDispatch();
    
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
        </div>
      );
    }
    
    function App() {
      return (
        <Provider store={store}>
          <Counter />
        </Provider>
      );
    }
    
  • zustand:

    Simple state management with zustand

    import create from 'zustand';
    
    // Create a store
    const useStore = create((set) => ({
      count: 0,
      increment: () => set((state) => ({ count: state.count + 1 })),
    }));
    
    function Counter() {
      const count = useStore((state) => state.count);
      const increment = useStore((state) => state.increment);
    
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={increment}>Increment</button>
        </div>
      );
    }
    
  • jotai:

    Simple state management with jotai

    import { atom, useAtom } from 'jotai';
    
    // Define an atom
    const countAtom = atom(0);
    
    function Counter() {
      const [count, setCount] = useAtom(countAtom);
    
      return (
        <div>
          <p>Count: {count}</p>
          <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
      );
    }
    
  • mobx:

    Reactive state management with mobx

    import { observable } from 'mobx';
    import { observer } from 'mobx-react';
    
    // Define an observable state
    const counter = observable({ count: 0 });
    
    const increment = () => {
      counter.count++;
    };
    
    const Counter = observer(() => (
      <div>
        <p>Count: {counter.count}</p>
        <button onClick={increment}>Increment</button>
      </div>
    ));
    
  • recoil:

    State management with recoil

    import { atom, selector, useRecoilState } from 'recoil';
    
    // Define an atom
    const countAtom = atom({
      key: 'countAtom', // unique ID (with respect to other atoms)
      default: 0,
    });
    
    // Define a selector
    const doubleCountSelector = selector({
      key: 'doubleCountSelector',
      get: ({ get }) => {
        const count = get(countAtom);
        return count * 2;
      },
    });
    
    function Counter() {
      const [count, setCount] = useRecoilState(countAtom);
      const doubleCount = useRecoilValue(doubleCountSelector);
    
      return (
        <div>
          <p>Count: {count}</p>
          <p>Double Count: {doubleCount}</p>
          <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
      );
    }
    
How to Choose: redux vs zustand vs jotai vs mobx vs recoil
  • redux:

    Choose redux if you need a robust, predictable state management solution with a strong ecosystem and middleware support. It is ideal for large applications that require a clear structure for managing state changes and handling complex logic.

  • zustand:

    Choose zustand if you want a minimalistic and lightweight state management solution with a simple API. It is perfect for small to medium-sized applications where you want to manage state without the complexity of larger libraries.

  • jotai:

    Choose jotai if you prefer a simple, atomic state management solution that integrates seamlessly with React. It is ideal for projects that require fine-grained control over state updates with minimal boilerplate.

  • mobx:

    Choose mobx if you need a reactive state management solution that automatically updates the UI when the state changes. It is suitable for applications where you want to minimize manual state management and prefer a more intuitive, observable-based approach.

  • recoil:

    Choose recoil if you want a state management library that provides a more React-like experience with support for derived state and asynchronous queries. It is great for applications that need a more flexible and composable way to manage state within React components.

README for redux

Redux Logo

Redux is a predictable state container for JavaScript apps.

It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.

You can use Redux together with React, or with any other view library. The Redux core is tiny (2kB, including dependencies), and has a rich ecosystem of addons.

Redux Toolkit is our official recommended approach for writing Redux logic. It wraps around the Redux core, and contains packages and functions that we think are essential for building a Redux app. Redux Toolkit builds in our suggested best practices, simplifies most Redux tasks, prevents common mistakes, and makes it easier to write Redux applications.

GitHub Workflow Status npm version npm downloads redux channel on discord

Installation

Create a React Redux App

The recommended way to start new apps with React and Redux Toolkit is by using our official Redux Toolkit + TS template for Vite, or by creating a new Next.js project using Next's with-redux template.

Both of these already have Redux Toolkit and React-Redux configured appropriately for that build tool, and come with a small example app that demonstrates how to use several of Redux Toolkit's features.

# Vite with our Redux+TS template
# (using the `degit` tool to clone and extract the template)
npx degit reduxjs/redux-templates/packages/vite-template-redux my-app

# Next.js using the `with-redux` template
npx create-next-app --example with-redux my-app

We do not currently have official React Native templates, but recommend these templates for standard React Native and for Expo:

  • https://github.com/rahsheen/react-native-template-redux-typescript
  • https://github.com/rahsheen/expo-template-redux-typescript
npm install @reduxjs/toolkit react-redux

For the Redux core library by itself:

npm install redux

For more details, see the Installation docs page.

Documentation

The Redux core docs are located at https://redux.js.org, and include the full Redux tutorials, as well usage guides on general Redux patterns:

The Redux Toolkit docs are available at https://redux-toolkit.js.org, including API references and usage guides for all of the APIs included in Redux Toolkit.

Learn Redux

Redux Essentials Tutorial

The Redux Essentials tutorial is a "top-down" tutorial that teaches "how to use Redux the right way", using our latest recommended APIs and best practices. We recommend starting there.

Redux Fundamentals Tutorial

The Redux Fundamentals tutorial is a "bottom-up" tutorial that teaches "how Redux works" from first principles and without any abstractions, and why standard Redux usage patterns exist.

Help and Discussion

The #redux channel of the Reactiflux Discord community is our official resource for all questions related to learning and using Redux. Reactiflux is a great place to hang out, ask questions, and learn - please come and join us there!

Before Proceeding Further

Redux is a valuable tool for organizing your state, but you should also consider whether it's appropriate for your situation. Please don't use Redux just because someone said you should - instead, please take some time to understand the potential benefits and tradeoffs of using it.

Here are some suggestions on when it makes sense to use Redux:

  • You have reasonable amounts of data changing over time
  • You need a single source of truth for your state
  • You find that keeping all your state in a top-level component is no longer sufficient

Yes, these guidelines are subjective and vague, but this is for a good reason. The point at which you should integrate Redux into your application is different for every user and different for every application.

For more thoughts on how Redux is meant to be used, please see:

Basic Example

The whole global state of your app is stored in an object tree inside a single store. The only way to change the state tree is to create an action, an object describing what happened, and dispatch it to the store. To specify how state gets updated in response to an action, you write pure reducer functions that calculate a new state based on the old state and the action.

Redux Toolkit simplifies the process of writing Redux logic and setting up the store. With Redux Toolkit, the basic app logic looks like:

import { createSlice, configureStore } from '@reduxjs/toolkit'

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0
  },
  reducers: {
    incremented: state => {
      // Redux Toolkit allows us to write "mutating" logic in reducers. It
      // doesn't actually mutate the state because it uses the Immer library,
      // which detects changes to a "draft state" and produces a brand new
      // immutable state based off those changes
      state.value += 1
    },
    decremented: state => {
      state.value -= 1
    }
  }
})

export const { incremented, decremented } = counterSlice.actions

const store = configureStore({
  reducer: counterSlice.reducer
})

// Can still subscribe to the store
store.subscribe(() => console.log(store.getState()))

// Still pass action objects to `dispatch`, but they're created for us
store.dispatch(incremented())
// {value: 1}
store.dispatch(incremented())
// {value: 2}
store.dispatch(decremented())
// {value: 1}

Redux Toolkit allows us to write shorter logic that's easier to read, while still following the original core Redux behavior and data flow.

Logo

You can find the official logo on GitHub.

Change Log

This project adheres to Semantic Versioning. Every release, along with the migration instructions, is documented on the GitHub Releases page.

License

MIT