Modern State Management: Beyond Redux—A Deep Dive into Architecture
9/12/2025
The real question is architecture, not library
I used Redux for years. It worked, but on some teams it came with too much ceremony for simple state updates.
Now I pick state tools based on architecture needs, not trend cycles. The hard part is not picking a library. The hard part is deciding what state belongs where.
What changed in practice
The biggest shift for me was moving from one giant store mindset to smaller, domain-shaped state.
- Components subscribe to less data
- Re-renders are easier to reason about
- Teams can refactor one slice without touching everything
That change alone improved performance debugging and onboarding speed on larger apps.
A practical state split I use
I separate state into three buckets before writing code:
- Local UI state (modal open, input draft, tab index)
- Client app state (cross-screen preferences, wizard progress)
- Server state (API data, cache, loading/error lifecycle)
Rule: I do not force server state into client global stores if a query library can own it better.
Performance habits that actually moved numbers
- Keep selectors/derived state small and explicit
- Avoid broad subscriptions to large objects
- Co-locate state with the feature unless reuse is proven
- Profile real screens before introducing complex optimization
In one dashboard project, just narrowing subscriptions removed a lot of noisy re-renders without any framework change.
How I structure code so it stays maintainable
I organize state by domain, not by state-tool primitives.
- `features/cart/state` owns cart state and hooks
- `features/auth/state` owns auth state and hooks
- UI code imports domain hooks, not internal atoms/store internals
This gives each feature a clean boundary and makes refactors less scary.
When teams get state wrong
- Everything becomes global too early
- Server and client state are mixed without clear ownership
- Optimization is added before measurement
- Feature teams bypass boundaries and read internals directly
I’ve made all four mistakes. Each one slows delivery later.
What I’d do differently if restarting
- Start with a clear state taxonomy on day one
- Use query libraries for server state from the start
- Document domain boundaries early
- Treat global state as expensive, not default
Closing checklist
- Can I explain why each state slice is local vs global?
- Is server state owned by the right tool?
- Do components subscribe only to what they need?
- Can a new engineer find state ownership quickly?
If yes, your state layer will scale better than the average "just pick a library" setup.