DEV Community

Cover image for Frontend System Design: Redux Toolkit vs Zustand vs Jotai
ZeeshanAli-0704
ZeeshanAli-0704

Posted on • Edited on

Frontend System Design: Redux Toolkit vs Zustand vs Jotai

🧠 Redux Toolkit vs Zustand vs Jotai — A Complete Guide to Choosing the Right State Management for React

"State is the memory of your application. How you manage it determines whether your app scales gracefully or collapses under its own weight."

As your React application grows beyond a handful of components, local state stops being enough. You start wrestling with shared data across screens, async API calls, caching, global UI flags, and predictable debugging. That's when you reach for a state management library — and immediately face the hardest decision: which one?

Redux Toolkit, Zustand, and Jotai are the three most popular React state management libraries today, and they solve the same fundamental problem in radically different ways. Picking the wrong one can mean months of refactoring. Picking the right one can save your team hundreds of hours.

This guide covers what each library does, why their mental models differ, when to choose which, performance and re-render behavior, middleware and DevTools, TypeScript and SSR support, scalability for teams, and the decision frameworks every React developer should know.


📚 Table of Contents

⬆ Back to Top


🔹 Why This Comparison Matters

The State Management Problem

Every non-trivial React application eventually faces these challenges:

Challenge What Happens Without Proper State Management
Shared data across screens Props drilled 6+ levels deep; components tightly coupled
Async API calls Loading/error states scattered across components; race conditions
Caching & deduplication Same API called multiple times; stale data shown to users
Global UI state Modals, toasts, sidebar toggles managed with ad-hoc context
Predictable debugging State changes impossible to trace; "how did this value get here?"
Multi-team collaboration Developers overwriting each other's state; merge conflicts

Why These Three?

The React state management landscape has dozens of libraries, but Redux Toolkit, Zustand, and Jotai represent the three fundamental paradigms:

Paradigm Library Philosophy
Flux / Centralized Redux Toolkit One global store, dispatched actions, pure reducers
Hook-based / Minimal Zustand Simple external store consumed via hooks, no ceremony
Atomic / Bottom-up Jotai Independent state atoms composed together, fine-grained

Understanding when and why to choose each paradigm is a core frontend architecture skill — and a top-tier interview topic.

⬆ Back to Top


🔹 Mental Models The Core Difference

Think of state management like organizing information in different ways:

Library Mental Model Real-World Analogy
Redux Toolkit Centralized enterprise data system A corporate filing system — everything goes through a central office, forms are filled out (actions), processed (reducers), and filed (store)
Zustand Simple global store with hooks A shared whiteboard — anyone can read it, anyone can update it, no paperwork needed
Jotai Atomic state pieces wired together Spreadsheet cells — each cell holds one value, and cells can reference (derive from) other cells

💡 Key Insight: The right choice depends on your app's complexity, team size, and how predictable you need state changes to be.

⬆ Back to Top


🔹 High Level Architecture

Redux Toolkit — Unidirectional Data Flow

Components dispatch actions (plain objects describing "what happened") → Reducers (pure functions) compute new state → Store holds the single source of truth → Components read state via selectors and re-render when their selected slice changes.

Key Properties: Single source of truth. Every state change is traceable. Middleware can intercept any action. Time-travel debugging is built in.

Zustand — Direct Store Access

Components import a hook → The hook reads state and exposes mutator functions → Calling a mutator updates the store directly → Only components whose selected slice changed re-render.

Key Properties: No actions, no reducers, no dispatch. Components read and write directly. Store lives outside React's component tree. No <Provider> wrapper required.

Jotai — Atomic State Graph

State is defined as small independent atoms → Components subscribe to individual atoms → Derived atoms automatically compute values from other atoms → When a base atom changes, only its subscribers and dependent derived atoms re-evaluate.

Key Properties: Each atom is independent. Dependencies are tracked automatically. Re-renders happen at the atom level — the most granular of all three. Atoms compose bottom-up.

⬆ Back to Top


🔹 Redux Toolkit RTK Overview

What It Is

Redux Toolkit (RTK) is the official, opinionated way to use Redux. Created by the Redux team to eliminate the biggest complaint — too much boilerplate — RTK wraps Redux with sensible defaults, built-in Immer for immutable updates, and a standardized slice pattern.

Core Concepts

Concept What It Does
Store Single object holding all app state
Slice State + reducers + auto-generated actions for one feature
Action Plain object describing "what happened" ({ type, payload })
Reducer Pure function: (currentState, action) → newState
Selector Function that extracts or derives data from the store
Thunk Async action creator for side effects (API calls, etc.)
RTK Query Built-in data fetching and caching layer
Middleware Intercepts actions between dispatch and the reducer

How Updates Flow

  1. Component calls dispatch(action)
  2. Middleware processes the action (logging, async, analytics)
  3. Reducer receives (currentState, action) and returns newState
  4. Store replaces its state reference
  5. All useSelector hooks re-evaluate
  6. Only components whose selector output changed will re-render

Strengths

Advantage Details
Best debugging experience Redux DevTools: time-travel, action log, state diff, action replay
Predictable state transitions Every change goes through action → reducer — easy to trace and test
First-class async support createAsyncThunk + RTK Query handle loading, error, and caching out of the box
Strong conventions Slices, selectors, thunks — clear patterns for any team member to follow
Massive ecosystem Redux Saga, Redux Observable, redux-persist, thousands of integrations
Battle-tested at scale Used by Instagram, Walmart, Twitch, Airbnb, and thousands of production apps
Excellent TypeScript support Fully typed with minimal boilerplate

Weaknesses

Disadvantage Details
More boilerplate than alternatives Even with RTK, you still write slices, selectors, thunks, store setup
Steeper learning curve Actions, reducers, selectors, middleware, thunks — many concepts to learn
Provider required Must wrap the entire app in <Provider store={store}>
Indirection Dispatching in Component A → reducer processes → Component B re-renders
Larger bundle ~13KB min+gzip (RTK + react-redux) — largest of the three

⬆ Back to Top


🔹 Zustand Overview

What It Is

Zustand (German for "state") is a minimal, un-opinionated global state library built entirely on React hooks. Created by Poimandres (the team behind react-three-fiber and drei), it strips away every abstraction Redux adds and gives you the simplest possible API.

No reducers. No actions. No dispatch. No provider. No ceremony.

Core Concepts

Concept What It Does
create() Creates a store and returns a custom hook
set() Merges partial state into the store
get() Reads the full current state (even outside React)
Selectors Pick specific slices to avoid unnecessary re-renders
subscribe() Listen to state changes outside React components
Middleware Composable wrappers (persist, devtools, immer)

How Updates Flow

  1. Component calls a mutator function directly (e.g., addItem(product))
  2. Mutator calls set() which merges new state into the store
  3. Zustand compares each subscriber's selected slice (via Object.is)
  4. Only components whose selected state changed will re-render

Strengths

Advantage Details
Extremely simple API Entire API surface: create, set, get, selectors — fits in a tweet
Minimal boilerplate No slices, no action types, no dispatch — just objects and functions
No Provider required Store lives outside React tree — no wrapper component needed
Tiny bundle size ~1.1KB min+gzip — roughly 10x smaller than RTK
Works outside React getState() and subscribe() work in vanilla JS, Node, or tests
Flexible middleware persist, devtools, immer, subscribeWithSelector — all composable
Fastest to prototype with Go from zero to working global state in under 5 minutes

Weaknesses

Disadvantage Details
No enforced structure Easy to create messy "god stores" with 50+ properties and no boundaries
Weaker debugging DevTools support exists via middleware, but not as rich as Redux time-travel
No built-in async conventions You write async logic manually — no equivalent to createAsyncThunk or RTK Query
Manual selector memoization No built-in createSelector — you need useShallow or manual equality checks
Hard to enforce at scale Without team conventions, 10 developers will write 10 different patterns

⬆ Back to Top


🔹 Jotai Overview

What It Is

Jotai (Japanese for "state") is built on the atomic state model inspired by Recoil. Instead of one centralized store, state is broken into the smallest possible independent pieces (atoms), which compose together to create derived state.

Created by Daishi Kato (who also contributes to Zustand and valtio), Jotai focuses on fine-grained reactivity — components only re-render when the specific atom they subscribe to changes.

Core Concepts

Concept What It Does
Primitive Atom Holds a single value (read + write)
Derived Atom (read-only) Computes a value from other atoms automatically
Derived Atom (read-write) Computes a value + has custom write logic
Async Atom Returns a Promise — integrates with React Suspense
useAtom() Hook to read + write an atom
useAtomValue() Hook to read only (no setter — no unnecessary re-renders)
useSetAtom() Hook to write only (no value subscription)
Provider Optional — scopes atoms to a subtree (useful for testing/SSR)
Atom Family Creates one atom per dynamic key (e.g., one per list item)

How Updates Flow

  1. Component calls setAtom(newValue) on a primitive or write atom
  2. The atom's value updates in Jotai's internal store
  3. All derived atoms that depend on it automatically re-compute
  4. Only components subscribed to changed atoms re-render

Jotai's dependency graph is automatic — when a derived atom reads another atom, Jotai tracks that dependency. When the source changes, the derived atom recalculates.

Strengths

Advantage Details
Most granular re-renders Components only re-render when the exact atom they read changes
Derived state is first-class Computed atoms are clean, automatic, and composable
Tiny bundle size ~2.4KB min+gzip
React Suspense integration Async atoms work natively with Suspense boundaries
No boilerplate Define an atom in one line, use it in one line
Bottom-up architecture Start with atoms, compose as needed — scales naturally with complexity
Atom families Dynamic atoms for lists/maps — avoids re-renders of unrelated items

Weaknesses

Disadvantage Details
Harder mental model "Atoms" and "derived atoms" require a paradigm shift from centralized stores
No central overview of state State is scattered across atom files — hard to see "the big picture"
Weakest debugging No built-in time-travel; Jotai DevTools exist but are less mature
Action tracing is difficult No action log — harder to answer "what changed this atom and why?"
Not ideal for very large teams Without strict conventions, atom organization can become chaotic
Smaller ecosystem Fewer middleware options and fewer Stack Overflow answers than Redux

⬆ Back to Top


🔹 Side by Side Feature Comparison

Feature Redux Toolkit Zustand Jotai
Bundle Size ~13KB (RTK + react-redux) ~1.1KB ~2.4KB
Boilerplate Medium Very Low Low
Mental Model Flux (actions + reducers) Hook-based mutable store Atomic state graph
Provider Required ✅ Yes ❌ No ⚠️ Optional
Debugging (DevTools) ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐
Time-Travel Debugging ✅ Built-in ❌ No ❌ No
Async Support Excellent (Thunks + RTK Query) Manual (inline async) Good (async atoms + Suspense)
Data Fetching / Caching RTK Query (built-in) External (TanStack Query) External (TanStack Query)
Middleware Extensive ecosystem persist, devtools, immer Atom utilities (storage, family)
Derived / Computed State createSelector (Reselect) Manual (via get()) First-class (derived atoms)
Re-render Granularity Selector-based Subscription-based Atom-level (most granular)
TypeScript Support ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐
SSR / Next.js ✅ Most mature ✅ Works (manual setup) ✅ Works (via Provider)
React Native ✅ Full support ✅ Full support ✅ Full support
Learning Curve Medium–High Low Medium
Scalability ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
Community & Ecosystem Massive Growing fast Growing
Best For Enterprise apps Small–mid apps Complex UI / fine-grained

⬆ Back to Top


🔹 Performance and Re render Behavior

Understanding re-render behavior is critical — unnecessary re-renders are the #1 performance problem in React apps.

How Each Library Triggers Re-renders

Library Strategy What Causes a Re-render What Does NOT Cause a Re-render
Redux Toolkit Selector-based (reference equality) Selector returns a new reference (!== previous) Unrelated state changes (selector returns same ref)
Zustand Subscription + shallow compare Selected state slice changes Unrelated state changes (different selector)
Jotai Atom-level subscription The specific atom the component reads changes Any atom the component did NOT subscribe to

Re-render Scenario

Consider an app with users, cart, and ui state. A user adds an item to the cart:

Component Redux Toolkit Zustand Jotai
CartBadge ✅ Re-renders (selector output changed) ✅ Re-renders (selected slice changed) ✅ Re-renders (cart atom changed)
UserList ❌ No re-render (different selector) ❌ No re-render (different slice) ❌ No re-render (different atom)
Sidebar ❌ No re-render (different selector) ❌ No re-render (different slice) ❌ No re-render (different atom)
Single product in a list of 100 ❌ Entire list re-renders ❌ Entire list re-renders ✅ Only THAT product re-renders (via atom family)

Performance Summary

Aspect Redux Toolkit Zustand Jotai
Default granularity Good Good Best
List item updates Re-renders list Re-renders list Re-renders one item (atom family)
Derived state performance Good (Reselect) Manual memoization Automatic (derived atoms)
Initial setup overhead Higher Minimal Minimal
Memory footprint Medium Small Small

💡 Rule of Thumb: For most apps, all three perform well enough. Jotai shines when you have large lists with frequent individual item updates — think design tools, spreadsheets, or real-time dashboards.

⬆ Back to Top


🔹 Middleware and DevTools

Redux Toolkit — Strongest Ecosystem

Middleware Purpose Built-in?
Redux DevTools Time-travel, action log, state diff, replay ✅ Yes
redux-thunk Async actions ✅ Yes
RTK Query Data fetching, caching, polling, invalidation ✅ Yes
redux-persist Persist state to localStorage / AsyncStorage Plugin
redux-saga Complex async flows (channels, forks, races) Plugin
redux-observable RxJS-based side effects Plugin
Custom middleware Logging, analytics, error reporting Easy

Zustand — Composable Middleware

Middleware Purpose Built-in?
devtools Connect to Redux DevTools ✅ Yes
persist Persist to localStorage / AsyncStorage ✅ Yes
immer Mutable-looking immutable updates ✅ Yes
subscribeWithSelector Fine-grained external subscriptions ✅ Yes
Custom middleware Wrap store creator with any logic Easy

Jotai — Atom Utilities

Utility Purpose
atomWithStorage Persist atom to localStorage
atomWithObservable Integrate with RxJS observables
atomFamily Dynamic atom creation (one per key)
selectAtom Derive with custom equality function
atomWithReducer Redux-style reducer for a single atom
loadable Handle async atom without Suspense
Jotai DevTools Inspect atom values in browser

DevTools Comparison

Capability Redux Toolkit Zustand Jotai
Action logging ✅ Full ⚠️ Via middleware ❌ No actions
State inspection ✅ Full ✅ Via middleware ⚠️ Basic
Time-travel ✅ Built-in ❌ No ❌ No
State diff ✅ Built-in ⚠️ Limited ❌ No
Action replay ✅ Built-in ❌ No ❌ No

⚠️ If your app deals with financial data, audit trails, or regulatory compliance, Redux Toolkit's debugging capabilities are a significant advantage.

⬆ Back to Top


🔹 TypeScript Support

Aspect Redux Toolkit Zustand Jotai
Auto-inference Good (from initialState) Needs explicit store interface Great (from atom initial value)
Typed hooks Requires defining typed wrappers Type comes free with create<T>() Hooks are generic automatically
IDE autocomplete Excellent Excellent Excellent
Selector type safety Full (via RootState type) Full (via store type) Full (via atom type)
Refactoring confidence High High High
Overall TS experience ⭐⭐⭐⭐⭐ (best documented) ⭐⭐⭐⭐ (clean, less setup) ⭐⭐⭐⭐ (most automatic)

⬆ Back to Top


🔹 SSR and Next.js Compatibility

Server-Side Rendering introduces unique challenges: state must be initialized on the server, serialized, and hydrated on the client without leaking between requests.

Aspect Redux Toolkit Zustand Jotai
SSR maturity Most mature Requires manual patterns Good (with Provider)
Per-request isolation ✅ via next-redux-wrapper ⚠️ Manual (React Context) ✅ via Provider
Hydration support Built-in with wrapper Manual rehydration needed useHydrateAtoms utility
Next.js App Router ✅ Well supported ✅ Works with patterns ✅ Works with Provider
Streaming SSR ✅ Works ✅ Works ✅ Works with Suspense
Risk of state leaks Low (well-documented) Medium (store is singleton) Low (Provider scopes state)

💡 If SSR correctness is critical (e.g., e-commerce with personalized data), Redux Toolkit has the most battle-tested patterns. Zustand requires the most manual care since its stores are singletons by default.

⬆ Back to Top


🔹 Scalability and Team Collaboration

Redux Toolkit — Enterprise Grade

Aspect Assessment
Team size Built for 10–100+ developers working in parallel
Feature isolation Each feature has its own slice, selectors, thunks — clear boundaries
Code review Actions and reducers are explicit — "what changed and why?" is clear
Onboarding Clear conventions → new devs productive in days
Merge conflicts Minimal — features don't touch each other's slices
Testing Reducers are pure functions — easiest to unit test of all three
Code splitting Reducers can be lazy-loaded per route

Zustand — Small Team Sweet Spot

Aspect Assessment
Team size Best for 1–5 developers
Feature isolation Requires team discipline; "slice pattern" helps but isn't enforced
Code review Harder — mutations happen inline, no formal action log
Onboarding Instant — API is trivial to learn
Merge conflicts Can happen if everyone edits the same store file
Testing Test by calling store actions and asserting state
Code splitting Not built-in, but stores are naturally separate files

Jotai — UI Complexity Champion

Aspect Assessment
Team size Best for 2–10 developers
Feature isolation Atoms can be organized by feature folder
Code review Harder — need to mentally trace atom dependency graph
Onboarding Medium — atomic mental model requires a paradigm shift
Merge conflicts Rare — atoms are small, independent files
Testing Test by rendering components with specific atom values
Code splitting Atoms are naturally code-split (only loaded when imported)

⬆ Back to Top


🔹 How to Choose Decision Frameworks

Decision Flowchart

Start
  │
  ├─ Is the app an enterprise product with 50+ screens?       ─── YES ──→ Redux Toolkit
  │
  ├─ Do multiple teams (5+) work on the same codebase?        ─── YES ──→ Redux Toolkit
  │
  ├─ Do you need time-travel debugging or action tracing?      ─── YES ──→ Redux Toolkit
  │
  ├─ Do you need built-in data fetching + caching (RTK Query)? ─── YES ──→ Redux Toolkit
  │
  ├─ Is the app small-to-medium (< 30 screens)?               ─── YES ──→ Zustand
  │
  ├─ Do you want the simplest possible setup?                  ─── YES ──→ Zustand
  │
  ├─ Do you need to access state outside React (vanilla JS)?   ─── YES ──→ Zustand
  │
  ├─ Is UI logic very complex with many derived values?        ─── YES ──→ Jotai
  │
  ├─ Do you need fine-grained re-renders for large lists?      ─── YES ──→ Jotai
  │
  ├─ Do you want native React Suspense integration?            ─── YES ──→ Jotai
  │
  └─ Not sure?  ──→ Start with Zustand, migrate to RTK if complexity grows
Enter fullscreen mode Exit fullscreen mode

Decision Matrix

Factor Redux Toolkit Zustand Jotai
App has 100+ screens ✅ Best choice ⚠️ Can work ⚠️ Can work
Multiple teams in parallel ✅ Best choice ❌ Gets messy ⚠️ Needs conventions
Long-term maintainability ✅ Best choice ⚠️ Needs discipline ⚠️ Needs discipline
Speed of development / prototyping ⚠️ Slower setup ✅ Best choice ✅ Fast
Prototyping / MVP ❌ Overkill ✅ Best choice ✅ Good
Complex derived state ⚠️ Reselect works ⚠️ Manual ✅ Best choice
Fine-grained reactivity ⚠️ With selectors ⚠️ With selectors ✅ Best choice
Design tools / spreadsheet-like UIs ❌ Too coarse ⚠️ Possible ✅ Best choice
Debugging-critical (finance, health) ✅ Best choice ⚠️ Limited ❌ Weakest
Smallest bundle size matters ❌ Largest (~13KB) ✅ Best (~1.1KB) ✅ Small (~2.4KB)
Server-side rendering ✅ Most mature ⚠️ Manual setup ✅ Good
Using state outside React ⚠️ Possible ✅ Best choice ❌ React-only

The "Classify First" Approach

Before choosing a library, classify what kind of state you actually have:

State Type Best Tool NOT This
Server/API data TanStack Query or RTK Query Don't manually fetch in stores
Client UI state RTK / Zustand / Jotai Don't use for API caching
URL state React Router / Next.js router Don't duplicate URL params in store
Form state React Hook Form / Formik Don't manage forms in global state
Derived state Selectors (RTK) / Derived atoms (Jotai) Don't store computed values

💡 Most apps need less global state than you think. If you classify first, you'll often find that 70% of your "state management problem" is actually a data fetching problem best solved by TanStack Query or RTK Query — not a store.

⬆ Back to Top


🔹 Real World Use Case Mapping

Scenario Best Choice Why
Enterprise dashboard (50+ screens) Redux Toolkit Predictable state, DevTools, feature isolation, RTK Query for APIs
E-commerce platform Redux Toolkit Cart, auth, products, orders — many domains needing async data and team collaboration
Chat application Redux Toolkit Message history, user presence, typing indicators — many async streams to coordinate
Multi-brand / white-label product Redux Toolkit Consistent architecture across brands, shared reducers, brand-specific slices
Admin panel / internal tool Zustand Simple CRUD, small team, fast development, minimal ceremony
Side project / personal app Zustand Fastest to set up, smallest bundle, no overthinking
Mobile app (React Native) Zustand Smallest bundle, simplest setup, great with React Navigation
Marketing site with dynamic UI Zustand or Jotai Lightweight, minimal state, fast page loads
Design tool (like Figma/Canva) Jotai Hundreds of independent objects on canvas, fine-grained updates, derived properties
Spreadsheet / data grid app Jotai Cell-level reactivity via atom families, derived formulas via derived atoms
Complex form with many dependencies Jotai Each field as an atom, validation as derived atoms, no unnecessary re-renders
Real-time collaborative editor Jotai + Zustand Jotai for document atoms, Zustand for connection/presence state

⬆ Back to Top


🔹 Migration Guidance

When to Migrate

From → To Trigger Signal
Zustand → Redux Toolkit App has grown, team has grown, debugging is painful, need stricter conventions
Zustand → Jotai Too many derived values computed manually, need fine-grained list updates
Redux Toolkit → Zustand App is simpler than expected, Redux overhead isn't paying off, team is very small
Jotai → Redux Toolkit Team can't trace state changes, need action logging, multiple teams joining

Migration Best Practices

  • Migrate one feature at a time — libraries can coexist during transition
  • Never do a big-bang rewrite — incremental migration reduces risk
  • Start with the most isolated feature — pick a feature with few cross-dependencies
  • Run both libraries in parallel — old features use old lib, new features use new lib
  • Delete old code only after new code is tested — don't leave dead state around

💡 Key Insight: All three libraries can coexist in the same app. A common production pattern is RTK Query or TanStack Query for server state, plus Zustand or Jotai for client/UI state.

⬆ Back to Top


🔹 Best Practices

General State Management

Practice Why
Classify your state first Server → TanStack Query. Client → RTK/Zustand/Jotai. URL → router. Form → form library
Don't put everything in global state Only shared, cross-component state belongs in a store
Derive, don't store Computed values belong in selectors / derived atoms, not in state
Normalize entity data Store lists as { ids: [], entities: {} } for O(1) lookups
Co-locate state with features Keep state logic near the components that use it
Separate server state from client state Use a data-fetching library for API data; use stores for UI state only

Redux Toolkit Specific

Practice Why
One slice per feature domain Clear ownership, easy to code-split
Use memoized selectors for all derived data Prevents unnecessary re-renders
Use RTK Query instead of manual thunks for API calls Built-in caching, polling, invalidation
Define typed hooks once, use everywhere Full TypeScript safety with zero per-component boilerplate
Keep reducers under 200 lines Split large slices into sub-slices when they grow

Zustand Specific

Practice Why
Always use selectors (useStore(s => s.field)) Prevents re-renders when unrelated state changes
Split into domain-specific stores Avoid "god stores" — useCartStore, useUserStore, useUIStore
Always enable devtools middleware Free debugging with no downside
Use persist for state that survives refresh Cart, user preferences, auth tokens
Use immer middleware for complex nested updates Cleaner syntax, fewer mutation bugs

Jotai Specific

Practice Why
Keep atoms small and focused (one value each) Don't create "object atoms" with 20 fields
Use useAtomValue for read-only, useSetAtom for write-only Prevents unnecessary subscriptions and re-renders
Group related atoms in feature folders atoms/cart/, atoms/auth/, atoms/ui/
Use atom families for dynamic / list data Avoids re-renders of unrelated list items
Document atom dependency graphs for your team Helps everyone understand what depends on what

⬆ Back to Top


🔹 State Management Checklist

Before Choosing a Library

✅ Classified state types (server vs client vs URL vs form)
✅ Identified which state actually needs to be global
✅ Assessed team size and experience level
✅ Evaluated app complexity (screen count, async flows, derived data)
✅ Considered long-term maintainability needs
✅ Checked SSR / Next.js requirements
✅ Reviewed debugging requirements (time-travel, action logging, audit trails)
✅ Evaluated bundle size constraints (mobile, low-bandwidth users)
Enter fullscreen mode Exit fullscreen mode

After Implementing

✅ Components subscribe to minimal state slices (not entire store)
✅ All derived data is computed (selectors / derived atoms), not stored
✅ Async operations handle loading, success, and error states
✅ Entity data is normalized where appropriate
✅ DevTools middleware is enabled in development
✅ Persisted state uses proper middleware (persist / atomWithStorage)
✅ Server state uses a data-fetching library, not manual fetches in stores
✅ TypeScript types are defined for all state shapes
✅ Feature state is co-located with feature components
Enter fullscreen mode Exit fullscreen mode

⬆ Back to Top


🔹 Key Interview Takeaways

"Compare Redux Toolkit, Zustand, and Jotai"

Redux Toolkit follows the Flux pattern — single centralized store, actions describe events, reducers compute new state. Best for large-scale enterprise apps where predictability, debugging, and team conventions matter most.

Zustand is a minimal hook-based external store — no actions, no reducers, no provider. Best for small-to-medium apps where speed and simplicity are the priority.

Jotai uses the atomic model — independent atoms that compose into derived state. Best for complex UIs needing fine-grained reactivity, like design tools or spreadsheets.

"When would you migrate from one to another?"

Start with Zustand for speed. If the app grows, teams multiply, or debugging becomes painful — migrate to Redux Toolkit for structure. If you discover performance bottlenecks due to coarse re-renders — reach for Jotai.

"What about performance?"

All three are fast enough for most apps. The difference shows up at scale: Redux uses selector-based re-renders (good), Zustand uses subscription-based (good), Jotai uses atom-level subscriptions (best granularity). For list-heavy UIs, Jotai's atom families avoid re-rendering the entire list when one item changes.

"Can they coexist?"

Yes. A common production pattern is RTK Query or TanStack Query for server state, plus Zustand or Jotai for client/UI state. They manage different concerns and don't conflict.

"If you had to pick one default?"

Zustand for most new projects — simplest API, smallest bundle, fastest time-to-value. Redux Toolkit if the project will be large, long-lived, or worked on by many teams.

⬆ Back to Top


🔹 Further Reading and Resources


More Details:

Get all articles related to system design
Hastag: SystemDesignWithZeeshanAli

systemdesignwithzeeshanali

Git: https://github.com/ZeeshanAli-0704/front-end-system-design

⬆ Back to Top

Top comments (0)