State Management at Scale
The Prompt
Design the state management architecture for an enterprise application with 50+ feature modules, real-time updates, offline capability, and 20+ developers contributing simultaneously.
State Categories
Not all state is equal. Categorize it:
| Category | Examples | Tool |
|---|---|---|
| Server state | API data, user profiles | React Query / SWR |
| Client state | UI toggles, form data | Zustand / Redux |
| URL state | Filters, pagination, tabs | URL search params |
| Form state | Input values, validation | React Hook Form |
| Derived state | Computed values, filtered lists | Selectors / useMemo |
Architecture
URL State (source of truth for shareable state)
â
Server State Cache (React Query â async, deduplicated)
â
Client Store (Zustand â UI state, preferences)
â
Component State (useState â ephemeral, local)
â
Derived State (selectors â computed, memoized)Server State with React Query
function useProducts(filters) {
return useQuery({
queryKey: ['products', filters],
queryFn: () => api.getProducts(filters),
staleTime: 30_000,
gcTime: 5 * 60_000,
placeholderData: keepPreviousData,
});
}- Automatic caching and deduplication
- Background refetching
- Optimistic updates for mutations
- DevTools for debugging
Client State with Zustand
const useUIStore = create((set) => ({
sidebarOpen: true,
activeModal: null,
toggleSidebar: () => set((s) => ({ sidebarOpen: !s.sidebarOpen })),
openModal: (id) => set({ activeModal: id }),
closeModal: () => set({ activeModal: null }),
}));URL State for Shareability
function useFilters() {
const [searchParams, setSearchParams] = useSearchParams();
const filters = useMemo(() => ({
category: searchParams.get('category') ?? 'all',
sort: searchParams.get('sort') ?? 'newest',
page: Number(searchParams.get('page') ?? 1),
}), [searchParams]);
const setFilter = useCallback((key, value) => {
setSearchParams((prev) => {
prev.set(key, value);
if (key !== 'page') prev.set('page', '1');
return prev;
});
}, [setSearchParams]);
return { filters, setFilter };
}Offline Support
- Persistence: Serialize critical state to IndexedDB
- Optimistic mutations: Apply changes locally, queue for server
- Conflict resolution: Last-write-wins or server-side merge
- Background sync: Service worker retries failed mutations
Guidelines for 20+ Developers
- Naming conventions â
use[Feature][Entity]for hooks - Co-location â state lives near the feature that uses it
- No global stores â except for truly global state (auth, theme)
- Documentation â each state slice has a README explaining its purpose
The senior insight: the best state management architecture is the one where most developers never think about state management. Make the right patterns the easy patterns.