# State Management Research: Redux vs Zustand vs Jotai

**Date**: 2026-02-14
**Focus**: State management for Normogen's encrypted health data platform
**Platform**: React Native + React (70-80% code sharing)

---

## Research Context

Normogen's state management requirements:

- **70-80% code sharing** between React Native and React
- **Complex state**: Family structure, multi-person profiles, permissions
- **Encrypted data**: All health data encrypted client-side
- **Offline synchronization**: Mobile-first with sync to server
- **TypeScript**: Full TypeScript codebase
- **Bundle size**: Mobile app needs to stay lightweight
- **Health sensors**: Real-time health data updates

---

## Options Overview

### 1. Redux (with Redux Toolkit)

**Description**: Industry-standard state management with predictable state container

**Latest Version**: Redux Toolkit 2.x (2024)

**Architecture**:
- Centralized store (single source of truth)
- Reducers for state updates (pure functions)
- Actions for state changes (dispatched events)
- Selectors for accessing state (memoized)
- Middleware for side effects (thunk, saga)

**Pros for Normogen**:
- **Mature ecosystem**: Largest community, extensive documentation
- **TypeScript support**: Excellent with Redux Toolkit
- **DevTools**: Best-in-class debugging tools
- **Middleware**: Great for async operations, sync logic
- **Normalization**: Ideal for family structure, profiles
- **Time-travel debugging**: Replay any state change
- **Code sharing**: 100% compatible with React Native + React
- **Battle-tested**: Used by large apps (Twitter, Uber, Facebook)

**Cons for Normogen**:
- **Boilerplate**: More setup than Zustand/Jotai
- **Bundle size**: Larger than Zustand/Jotai (47KB minzipped)
- **Learning curve**: More concepts to learn (actions, reducers, middleware)
- **Overkill**: May be complex for smaller use cases

**Bundle Size Impact**:
- Redux Toolkit: ~47KB minzipped
- React-Redux: ~13KB minzipped
- Total: ~60KB minzipped

**TypeScript Support**: Excellent (Redux Toolkit built with TypeScript)

**Code Sharing**: 100% between React Native and React

---

### 2. Zustand

**Description**: Minimal, fast state management using React hooks

**Latest Version**: Zustand 4.x (2024)

**Architecture**:
- Hook-based store (useStore)
- Actions are functions (no dispatch, no reducers)
- No providers (no need to wrap app)
- Built-in devtools, persistence, middleware

**Pros for Normogen**:
- **Simple**: Minimal API, easy to learn
- **Boilerplate**: Much less than Redux
- **Bundle size**: Tiny (~3KB minzipped)
- **Performance**: No re-renders with selectors
- **TypeScript**: Excellent support
- **Code sharing**: 100% compatible with React Native + React
- **Modern**: Built for React hooks, no legacy patterns
- **DevTools**: Built-in debugging
- **Persistence**: Built-in middleware for async storage
- **No providers**: Simpler app structure

**Cons for Normogen**:
- **Smaller ecosystem**: Less mature than Redux
- **Less battle-tested**: Fewer large-scale deployments
- **No time-travel debugging**: Cannot replay state changes easily
- **Normalization**: No built-in state normalization
- **Async middleware**: Less mature than Redux

**Bundle Size Impact**:
- Zustand core: ~3KB minzipped
- Immer included: Built-in
- Total: ~3KB minzipped

**TypeScript Support**: Excellent (built with TypeScript)

**Code Sharing**: 100% between React Native and React

---

### 3. Jotai

**Description**: Primitive and flexible state management for React

**Latest Version**: Jotai 2.x (2024)

**Architecture**:
- Atomic state (small, independent pieces of state)
- Hook-based (atom families, useAtom)
- Bottom-up (compose state from primitives)
- No providers (optional, but recommended)

**Pros for Normogen**:
- **Minimal**: Smallest bundle size (~3KB)
- **Flexible**: Can model any state architecture
- **Performance**: Only re-renders components using specific atoms
- **TypeScript**: Excellent support
- **Code sharing**: 100% compatible with React Native + React
- **Modern**: Latest React patterns, hooks-based
- **Composable**: Build complex state from simple atoms
- **DevTools**: Built-in debugging
- **React Concurrent**: Optimized for React 18 concurrent features

**Cons for Normogen**:
- **Smallest ecosystem**: Less mature than Zustand
- **Newest**: Less proven in production
- **Learning curve**: Atomic model may be unfamiliar
- **Less structure**: No enforced patterns (flexibility can be double-edged)
- **Fewer tutorials**: Harder to find best practices
- **No time-travel debugging**: Cannot replay state changes

**Bundle Size Impact**:
- Jotai core: ~3KB minzipped
- Immer included: Built-in
- Total: ~3KB minzipped

**TypeScript Support**: Excellent (built with TypeScript)

**Code Sharing**: 100% between React Native and React

---

## Comparison Matrix

| Criterion | Redux Toolkit | Zustand | Jotai |
|-----------|---------------|----------|--------|
| **Bundle Size** | 60KB | 3KB | 3KB |
| **Boilerplate** | High | Low | Low |
| **Learning Curve** | Steep | Gentle | Moderate |
| **Ecosystem** | Largest | Large | Medium |
| **TypeScript** | Excellent | Excellent | Excellent |
| **DevTools** | Best | Good | Good |
| **Time-Travel Debug** | Yes | No | No |
| **Code Sharing** | 100% | 100% | 100% |
| **Maturity** | Very High | High | Medium |
| **Performance** | Good | Excellent | Excellent |
| **Normalization** | Built-in | Manual | Manual |
| **Async Middleware** | Excellent | Good | Good |
| **Battle-Tested** | Excellent | Good | Fair |
| **Community** | Largest | Large | Medium |
| **Documentation** | Excellent | Good | Good |
| **Mobile Support** | Excellent | Excellent | Excellent |

---

## Normogen-Specific Analysis

### 1. Code Sharing (Critical: 70-80%)

All three options (Redux, Zustand, Jotai) are 100% compatible with both React Native and React.

**Verdict**: Tie (all excellent)

---

### 2. Bundle Size (Critical: Mobile App)

- **Redux Toolkit**: 60KB (larger impact on mobile app size)
- **Zustand**: 3KB (negligible impact)
- **Jotai**: 3KB (negligible impact)

**Analysis**:
- For a mobile app, 60KB is significant (may affect download size)
- However, total React Native app will be 50-100MB anyway
- 60KB is <0.1% of total app size
- Performance impact is negligible on modern phones

**Verdict**: Zustand/Jotai win, but not critical

---

### 3. TypeScript Support (Critical: Full TypeScript Codebase)

All three options have excellent TypeScript support:

- **Redux Toolkit**: Built with TypeScript, full type safety
- **Zustand**: Built with TypeScript, full type safety
- **Jotai**: Built with TypeScript, full type safety

**Verdict**: Tie (all excellent)

---

### 4. Complex State (Critical: Family Structure, Multi-Person Profiles)

**Use Case**: Managing family structure with parents, children, elderly, and access permissions

**Redux Toolkit (Best)**:
- Built-in normalization (Redux Toolkit createEntityAdapter)
- Enforced patterns (reducers, actions)
- Predictable state updates
- Easy to debug complex state interactions
- Time-travel debugging for complex state trees

**Zustand (Good)**:
- No built-in normalization
- Can manually normalize state
- More flexibility, but less structure
- Harder to debug complex state interactions

**Jotai (Fair)**:
- Atomic state model
- Can normalize, but no built-in patterns
- Most flexibility, but least structure
- Hardest to debug complex state interactions

**Verdict**: Redux Toolkit wins for complex state

---

### 5. Offline Synchronization (Critical: Mobile-First)

**Use Case**: Sync encrypted health data to server when offline, handle conflicts

**Redux Toolkit (Best)**:
- **Redux Toolkit RTK Query**: Excellent for server state
- Built-in optimistic updates
- Automatic cache invalidation
- Background sync support
- Battle-tested offline patterns
- Redux Saga for complex async flows

**Zustand (Good)**:
- Can build sync with middleware
- No built-in server state management
- Need to build sync logic manually
- Can use RTK Query with Zustand (but why not use Redux?)

**Jotai (Fair)**:
- Can build sync with atoms
- No built-in server state management
- Need to build sync logic manually
- Least proven for offline sync

**Verdict**: Redux Toolkit wins for offline sync

---

### 6. Encrypted Data Caching (High Priority)

**Use Case**: Cache encrypted health data locally, decrypt on demand

**Redux Toolkit (Best)**:
- Normalized state ideal for caching
- Selectors for efficient data access
- Persist entire store to AsyncStorage
- Redux Persist middleware built-in

**Zustand (Good)**:
- Built-in persistence middleware (zustand/persist)
- Can cache encrypted data
- Manual normalization

**Jotai (Good)**:
- Can persist atoms to AsyncStorage
- Can cache encrypted data
- Manual normalization

**Verdict**: Redux Toolkit wins, but Zustand is close second

---

### 7. Learning Curve (Medium Priority)

**Team Considerations**:
- Team knows JavaScript/TypeScript
- Team may not know React Native deeply
- Need to ship mobile app quickly

**Redux Toolkit**: Steep learning curve
- Concepts: actions, reducers, middleware, selectors, normalization
- More boilerplate to write
- More patterns to learn

**Zustand**: Gentle learning curve
- Simple API: createStore, useStore
- Less boilerplate
- Easier to get started

**Jotai**: Moderate learning curve
- Concept: atomic state (may be unfamiliar)
- Less boilerplate than Redux
- More structure than Zustand

**Verdict**: Zustand wins for ease of learning

---

### 8. Developer Experience (Medium Priority)

**Redux Toolkit (Best)**:
- Best DevTools (Redux DevTools)
- Time-travel debugging
- Predictable state updates
- Easy to debug
- More verbose, but clearer

**Zustand (Good)**:
- Good DevTools (Zustand DevTools)
- Less code to write
- Simpler, but less structure
- Easier to write, harder to debug

**Jotai (Good)**:
- Good DevTools (Jotai DevTools)
- Less code to write
- Most flexible, but least structure
- Hardest to debug

**Verdict**: Redux Toolkit wins for debugging

---

### 9. Ecosystem Maturity (Medium Priority)

**Redux Toolkit**: Very mature
- Largest ecosystem
- Most tutorials, blog posts, StackOverflow answers
- Most libraries (Redux Toolkit, RTK Query, Redux Saga)
- Most production deployments
- Easy to hire developers

**Zustand**: Mature
- Large ecosystem
- Good tutorials, blog posts, StackOverflow answers
- Many production deployments
- Easy to hire developers

**Jotai**: Less mature
- Smaller ecosystem
- Fewer tutorials, blog posts, StackOverflow answers
- Fewer production deployments
- Harder to hire developers

**Verdict**: Redux Toolkit wins for ecosystem maturity

---

### 10. Health Sensor Integration (Low Priority)

**Use Case**: Real-time health data updates (steps, heart rate, sleep)

All three options handle real-time updates equally well:
- React Native Health provides callbacks
- Updates dispatched to store
- No significant difference

**Verdict**: Tie (all good)

---

## Scorecard

| Criterion | Redux Toolkit | Zustand | Jotai | Weight |
|-----------|---------------|----------|--------|--------|
| **Code Sharing** | 10 | 10 | 10 | Critical |
| **Bundle Size** | 7 | 10 | 10 | Critical |
| **TypeScript** | 10 | 10 | 10 | Critical |
| **Complex State** | 10 | 7 | 5 | Critical |
| **Offline Sync** | 10 | 7 | 5 | Critical |
| **Encrypted Cache** | 10 | 8 | 8 | High |
| **Learning Curve** | 6 | 9 | 8 | Medium |
| **DevTools** | 10 | 7 | 7 | Medium |
| **Ecosystem** | 10 | 8 | 6 | Medium |
| **Health Sensors** | 10 | 10 | 10 | Low |
| **Weighted Score** | 9.2 | 8.6 | 7.6 | - |

---

## Recommendation

### Primary Recommendation: **Redux Toolkit**

**Score**: 9.2/10

**Justification**:

1. **Complex State Management** (Critical)
   - Best for family structure, multi-person profiles, permissions
   - Built-in normalization (Redux Toolkit createEntityAdapter)
   - Predictable state updates
   - Time-travel debugging

2. **Offline Synchronization** (Critical)
   - RTK Query for server state management
   - Optimistic updates
   - Background sync support
   - Battle-tested offline patterns

3. **Ecosystem Maturity** (Medium)
   - Largest ecosystem
   - Most resources, tutorials, examples
   - Most production deployments
   - Easiest to hire developers

4. **Developer Experience** (Medium)
   - Best DevTools (Redux DevTools)
   - Time-travel debugging
   - Predictable state updates
   - Easy to debug

**Trade-offs**:
- **More boilerplate**: More code to write, but clearer structure
- **Steeper learning curve**: More concepts to learn, but better patterns
- **Larger bundle**: 60KB vs 3KB (negligible impact on 50-100MB app)

**Verdict**: Redux Toolkit is the best choice for Normogen's complex state management needs

---

### Alternative Considered: Zustand

**Score**: 8.6/10

**Why Zustand is a strong alternative**:

1. **Simplicity**: Less boilerplate, easier to learn
2. **Bundle Size**: 3KB vs 60KB (negligible impact)
3. **Performance**: Excellent performance, no re-renders
4. **Modern**: Built for React hooks, no legacy patterns

**Why Redux Toolkit wins**:

1. **Complex State**: Redux has built-in normalization, enforced patterns
2. **Offline Sync**: RTK Query is excellent for server state
3. **Ecosystem**: Larger ecosystem, more resources
4. **Debugging**: Time-travel debugging for complex state trees

**When to use Zustand instead**:
- If team has no Redux experience
- If state is simpler (no family structure)
- If development speed is more important than structure
- If 60KB bundle size is critical (not the case here)

---
## Technology Stack with Redux Toolkit

### Mobile (React Native)
- **Framework**: React Native 0.73+
- **Language**: TypeScript
- **State Management**: Redux Toolkit 2.x
- **Data Fetching**: RTK Query 2.x
- **Async Thunks**: Redux Toolkit createAsyncThunk
- **Persistence**: Redux Persist 6.x (AsyncStorage)
- **DevTools**: Redux DevTools (React Native Debugger)

### Web (React)
- **Framework**: React 18+
- **Language**: TypeScript
- **State Management**: Redux Toolkit 2.x
- **Data Fetching**: RTK Query 2.x
- **Async Thunks**: Redux Toolkit createAsyncThunk
- **Persistence**: Redux Persist 6.x (localStorage)
- **DevTools**: Redux DevTools (Browser Extension)

### Shared (Monorepo)
- **Language**: TypeScript
- **State Management**: Redux Toolkit 2.x
- **Reducers**: Shared reducers (user, family, encryption)
- **Selectors**: Shared selectors (memoized with Reselect)
- **Types**: Shared TypeScript types
- **Actions**: Shared action creators
- **Middleware**: Shared middleware (logging, crash reporting)

---

## Implementation Example: Family Structure

### State Slice (Redux Toolkit)

```typescript
// shared/store/slices/familySlice.ts
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit';
import type { EntityState } from '@reduxjs/toolkit';

export interface FamilyMember {
  id: string;
  name: string;
  role: 'parent' | 'child' | 'elderly';
  permissions: string[];
  profileId: string;
}

const familyAdapter = createEntityAdapter<FamilyMember>({
  selectId: (member) => member.id,
  sortComparer: (a, b) => a.name.localeCompare(b.name),
});

interface FamilyState extends EntityState<FamilyMember> {
  currentFamilyId: string | null;
  isLoading: boolean;
  error: string | null;
}

const initialState: FamilyState = {
  currentFamilyId: null,
  isLoading: false,
  error: null,
  ...familyAdapter.getInitialState(),
};

export const familySlice = createSlice({
  name: 'family',
  initialState,
  reducers: {
    familyMemberAdded: familyAdapter.addOne,
    familyMemberUpdated: familyAdapter.updateOne,
    familyMemberRemoved: familyAdapter.removeOne,
    setCurrentFamily: (state, action) => {
      state.currentFamilyId = action.payload;
    },
  },
});

export const {
  familyMemberAdded,
  familyMemberUpdated,
  familyMemberRemoved,
  setCurrentFamily,
} = familySlice.actions;

export const {
  selectAll: selectAllFamilyMembers,
  selectById: selectFamilyMemberById,
  selectIds: selectFamilyMemberIds,
} = familyAdapter.getSelectors();

export default familySlice.reducer;
```

### Async Thunk (Offline Sync)

```typescript
// shared/store/thunks/syncFamilyMembers.ts
import { createAsyncThunk } from '@reduxjs/toolkit';
import { apiClient } from '../api/client';
import { decryptFamilyMembers, encryptFamilyMembers } from '../crypto';

export const syncFamilyMembers = createAsyncThunk(
  'family/syncFamilyMembers',
  async (_, { getState }) => {
    const state = getState() as RootState;
    const { lastSyncTime } = state.family;
    
    // Fetch encrypted family members from server
    const response = await apiClient.get('/api/family/sync', {
      params: { since: lastSyncTime },
    });
    
    // Decrypt on client-side
    const familyMembers = await decryptFamilyMembers(
      response.data.encryptedData,
      state.encryption.key,
    );
    
    return familyMembers;
  }
);
```

### RTK Query (Data Fetching)

```typescript
// shared/store/api/healthDataApi.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { apiClient } from '../api/client';

export const healthDataApi = createApi({
  reducerPath: 'healthDataApi',
  baseQuery: fetchBaseQuery({
    baseUrl: '/api',
    prepareHeaders: (headers, { getState }) => {
      const token = (getState() as RootState).auth.token;
      if (token) headers.set('authorization', `Bearer ${token}`);
      return headers;
    },
  }),
  tagTypes: ['HealthData'],
  endpoints: (builder) => ({
    getHealthData: builder.query<EncryptedHealthData, string>({
      query: (profileId) => `/health-data/${profileId}`,
      providesTags: ['HealthData'],
    }),
    updateHealthData: builder.mutation<void, UpdateHealthDataRequest>({
      query: ({ profileId, data }) => ({
        url: `/health-data/${profileId}`,
        method: 'POST',
        body: data,
      }),
      invalidatesTags: ['HealthData'],
    }),
  }),
});

export const { useGetHealthDataQuery, useUpdateHealthDataMutation } = healthDataApi;
```

---

## Proof of Concept Requirements

### Redux Toolkit POC

1. **Family Structure State**
   - Create family slice with normalized state
   - Add/update/remove family members
   - Manage permissions
   - Test selectors

2. **Offline Sync**
   - Implement RTK Query for server state
   - Implement optimistic updates
   - Test background sync
   - Handle conflicts

3. **Encrypted Data Caching**
   - Persist encrypted data to AsyncStorage
   - Decrypt on demand
   - Test performance with large datasets

4. **TypeScript Types**
   - Full type safety
   - Shared types between mobile and web
   - Test type inference

### Zustand Alternative POC

1. **Family Structure State**
   - Create family store with Zustand
   - Add/update/remove family members
   - Manage permissions
   - Test selectors

2. **Offline Sync**
   - Implement custom sync middleware
   - Test background sync
   - Handle conflicts

3. **Encrypted Data Caching**
   - Persist encrypted data to AsyncStorage
   - Decrypt on demand
   - Test performance with large datasets

---

## Risk Assessment

### Redux Toolkit Risks

| Risk | Severity | Mitigation |
|------|----------|------------|
| Steep learning curve | Medium | Team training, good documentation |
| More boilerplate | Low | Redux Toolkit reduces boilerplate significantly |
| Larger bundle size | Low | 60KB is negligible for 50-100MB app |
| Over-engineering | Low | Normogen has complex state needs |
| Performance | Low | Redux is fast enough for health app |

### Zustand Risks

| Risk | Severity | Mitigation |
|------|----------|------------|
| Less structure | Medium | Need to enforce patterns manually |
| Complex state harder | Medium | More difficult for family structure |
| Offline sync less mature | Medium | Need to build sync logic manually |
| Less ecosystem | Low | Zustand ecosystem is large enough |

---

## Conclusion

### Primary Recommendation: Redux Toolkit 2.x

**Score**: 9.2/10

**Key Advantages**:

1. **Best for Complex State**: Family structure, multi-person profiles, permissions
2. **Best for Offline Sync**: RTK Query, optimistic updates, background sync
3. **Best Ecosystem**: Largest ecosystem, most resources, easiest to hire
4. **Best Developer Experience**: Time-travel debugging, predictable state updates
5. **TypeScript**: Excellent support, full type safety
6. **Code Sharing**: 100% between React Native and React

**Trade-offs**:
- More boilerplate: More code, but clearer structure
- Steeper learning curve: More concepts, but better patterns
- Larger bundle: 60KB vs 3KB (negligible impact)

**Verdict**: Redux Toolkit is the best choice for Normogen's encrypted health data platform

---

### Alternative: Zustand 4.x

**Score**: 8.6/10

**When to use Zustand instead**:
- If team has no Redux experience
- If state is simpler (no family structure)
- If development speed is more important than structure

---

## Next Steps

1. Implement Redux Toolkit POC
2. Create family structure state slice
3. Implement RTK Query for server state
4. Test offline synchronization
5. Test encrypted data caching
6. Evaluate developer experience
7. Make final decision

---

## References

- [Redux Toolkit Documentation](https://redux-toolkit.js.org/)
- [RTK Query Documentation](https://redux-toolkit.js.org/rtk-query/overview)
- [Redux Persist](https://github.com/rt2zz/redux-persist)
- [Zustand Documentation](https://github.com/pmndrs/zustand)
- [Jotai Documentation](https://jotai.org/)
- [React Redux](https://react-redux.js.org/)
- [Reselect](https://github.com/reduxjs/reselect)
