State Management (Jotai)
Relevant source files
The following files were used as context for generating this wiki page:
Jotai serves as the primary global state management library within the Twenty frontend ecosystem. It is utilized to manage primitive state, derived state (selectors), and dynamic collections (atom families) that need to be accessed across multiple components without prop drilling.
In the Twenty architecture, Jotai complements React's built-in state hooks and Apollo Client's GraphQL cache. While Apollo handles server-side data synchronization, Jotai manages client-side UI state, global configurations, and shared registries like icons and themes.
Sources: CLAUDE.md:116-121, packages/twenty-ui/README.md:106-115
Core State Principles
The project adheres to specific development principles to ensure state remains predictable and performant:
- Functional State Updates: Updates to state should use functional forms, such as
setState(prev => prev + 1), to ensure accuracy when multiple updates occur. - Unidirectional Data Flow: State follows a "props down, events up" pattern.
- Decoupled State: Reusable UI components are designed to be decoupled from global stores (Jotai atoms) where possible, preferring controlled props to maintain library independence.
- Event Handlers over useEffect: For state updates triggered by user actions or lifecycle events, event handlers are preferred over
useEffectto avoid unnecessary re-renders.
Sources: CLAUDE.md:80-84, packages/twenty-ui/README.md:150-155, packages/twenty-codex-plugin/references/develop-app/app-structure.md:80-85
State Architecture
The state management architecture is divided into three primary layers: Atomic State, Derived State, and External Data Cache.
Atomic State Layers
The following diagram illustrates the relationship between Jotai atoms, component interactions, and the external Apollo cache.
This diagram shows how React components interact with Jotai for local UI state while utilizing Apollo for server-synced data.
Sources: CLAUDE.md:116-121, packages/twenty-ui/README.md:150-155
Implementation Details
Key State Components and Atoms
Twenty utilizes several specific atoms and providers to manage global UI registries:
| Component/Atom | Description | Path |
|---|---|---|
IconsProvider | A Jotai-backed registry for the icon system. | packages/twenty-ui |
invalidAvatarUrlsAtomV2 | Manages state for broken-image fallbacks in the Avatar component. | packages/twenty-ui/src/display |
iconsState | Global atom for tracking icon availability and registration. | packages/twenty-ui/src/display |
ThemeProvider | Uses Jotai context to manage runtime CSS-variable parsing and theme switching. | packages/twenty-ui/src/theme |
Sources: packages/twenty-ui/README.md:106-115, packages/twenty-codex-plugin/CHANGELOG.md:117-120
Logic and Data Flow (Sequence)
The interaction between a user action and the state update mechanism typically follows this sequence:
This sequence ensures that UI updates are reactive and focused only on components that subscribe to specific atoms.
Sources: CLAUDE.md:81-84, packages/twenty-ui/README.md:150-160
State Decoupling in twenty-ui
In the twenty-ui package, the architecture emphasizes removing internal Jotai dependencies for generic components. This "headless" or "controlled" approach ensures that the UI library can be published as a standalone package without being tightly coupled to the application's global store.
Generic vs. App-Specific State
- Generic Components: Use controlled props (e.g.,
isOpen,onOpenChange) instead of reading from global atoms. - Hybrid Components: May contain a presentational core in the library and an app-wired wrapper in the frontend that connects to Jotai.
Sources: packages/twenty-ui/README.md:150-165, packages/twenty-codex-plugin/references/develop-app/app-structure.md:80-85
Conclusion
State management in Twenty is a hybrid system where Jotai handles the reactive, client-side global state, while Apollo Client manages the complex server-side data cache. By adhering to functional update patterns and unidirectional data flow, the project maintains a clear separation between UI behavior and business logic. The ongoing migration in the twenty-ui package further promotes decoupling global state from presentational components to increase modularity and testability across the monorepo.
Sources: CLAUDE.md:116-121, packages/twenty-ui/README.md:144-148