Yashveer Singh
Connect
<- All posts
Web App and Frontend Development12 min read

The State Management Question in 2026

State management in React has fragmented into several credible answers, each suited to a different kind of problem. The choice in 2026 is not Redux versus Zustand. It is a question of what kind of state you have, where it lives, and whether a library is even the right tool. Most teams over-architect this early and pay for it later.

Written by Yashveer Singh, founder of Yashveer Labs.

What you actually need to know

  • Server Components have genuinely shrunk the client-side state problem for App Router apps.
  • Zustand and Jotai have replaced Redux for most new projects. The mental model is lighter and the results are the same.
  • React Query and SWR own server state. Mixing server state into a global store is a pattern worth avoiding.
  • URL state is real state. Filters, pagination, and sort order belong in the URL, not in a store.
  • In my experience, most teams over-invest in state tooling early and spend months undoing it.
ToolBest forWatch out for
ZustandGlobal client state, cross-component sharingNot a server state solution; keep it for UI state
JotaiFine-grained atom state, derived state without re-rendersAtom proliferation can get messy without discipline
Redux ToolkitLarge teams, established codebases, strong devtools needOverhead rarely justified on new greenfield apps
React Query / SWRServer state, caching, background revalidationNot a replacement for global UI state
React ContextApp config, theme, auth, infrequently changing valuesRe-render cost kills it for high-frequency state
URL stateFilters, pagination, tab selection, searchNeeds discipline to keep in sync with UI

The core argument

State management is a category, not a tool. The question is not which library to use. The question is what kind of state you have. Server state and client state are different problems. Routing state and ephemeral form state are different problems. A team that answers the category question first makes better library choices.

Server state is state that lives on the server and gets fetched over the network. It has a loading state, an error state, a stale state, and a refetch requirement. React Query and SWR were built for this. Putting server state into a global store like Redux or Zustand is not wrong, exactly, but it forces you to manage cache invalidation, loading states, and background refresh by hand. That is wheel re-invention.

Client state is state that lives in the browser and is not persisted to a server. Modal open or closed. Selected tab. Sidebar collapsed. Filter values that affect display but not the URL. This is what Zustand and Jotai are built for. The libraries are light. The APIs are simple. There is no ceremony.

URL state is the most underused category. The URL is the oldest global state store in web development. Filters, pagination, search queries, and tab selections belong in the URL because they survive page refresh, can be bookmarked, and can be shared. Teams that keep these values in a client store produce pages that reset on refresh and cannot be linked. The fix is to move them to URL params, which in Next.js means useSearchParams and router.replace.

Context is not a state management solution. It is a dependency injection mechanism. It gets misused as a poor-person's Redux, and the re-render cost eventually becomes visible. Theme, locale, current user, and feature flags are the natural fit. Form state, filter state, and anything that updates on user input are not.

How state splits across a modern Next.js app

Server state

Data fetched from an API or database. In App Router, much of this lives in Server Components and never touches the client state layer at all. For the data you do need on the client, React Query is the clearest answer in 2026. The devtools are good. The mutation patterns are explicit. The cache invalidation story is coherent.

Global UI state

Things that multiple components care about: the current user's preferences, whether a modal is open, the state of a shared panel. Zustand is the right tool for this. A small store. Selectors to avoid unnecessary re-renders. No reducers, no dispatch.

Local component state

useState and useReducer. Most state lives here and should stay here. The biggest mistake teams make is lifting state too early. If only one component needs a value, that component owns it.

Form state

React Hook Form or TanStack Form. Neither belongs in a global store. Forms have their own lifecycle. The validation, submission, and error state are co-located with the form component. Lifting form state into a global store creates coupling that eventually breaks.

What it actually requires

State categoryRecommended toolSetup cost
Server data fetchingReact Query or SWRLow, one provider at the app root
Global UI stateZustandVery low, one file per store
Atom-based fine-grained stateJotaiVery low, no provider needed
URL filters and paginationuseSearchParams + routerZero, built into Next.js
Form stateReact Hook FormLow, per form
Auth and configReact ContextLow, one context at the app root

Features to demand from your state layer

  • Clear separation between server state and client state. They have different shapes and different tools.
  • Selectors everywhere. Components should subscribe to only the state they use.
  • Devtools support. Zustand has them. React Query has them. If you cannot inspect state in the browser, debugging is harder than it needs to be.
  • A clear owner for URL state. One hook or utility that all filter components use to read and write URL params.
  • A rule about Context. What goes in it, what does not, and why.
  • Documentation that a new team member can read in twenty minutes and understand the state boundaries.

Expert opinion

The teams that get state management right are the ones that ask "does this need to be global?" before reaching for a library. Most state does not. A surprising amount of what teams put into stores would be cleaner as URL state or local state. The complexity of a state layer grows with the number of things it manages. Keep it small on purpose.

>

Yashveer Singh, founder of Yashveer Labs

How this played out on a real project

On a SaaS dashboard I built in late 2025, we started with Zustand for everything. Two months in, the store had grown to include server data, form state, filter values, and UI state. The component re-renders were frequent and the debugging sessions were long. We spent a week splitting it. Server data moved to React Query. Filter values moved to URL params. Form state moved into React Hook Form. The Zustand store shrank to about four UI flags. The app was faster and easier to reason about.

For a different project, a marketing site with some interactive elements, the answer was no library at all. useState for the interactive bits, URL params for the filter, and Server Components for the data. The whole thing took an afternoon to wire up. The lesson was that the right state tool is sometimes no state tool.

For more context on the broader architecture, the App Router versus Pages Router migration decision covers how the router choice affects the state question directly, and the frontend architecture that survives three years of feature sprawl covers the broader sustainability frame.

Common mistakes teams make

  1. Using a global store for server state. Server state has its own lifecycle. A dedicated library handles it better.
  2. Putting form state into a global store. Forms are self-contained. The coupling breaks things later.
  3. Using Context for high-frequency updates. The re-render cost is real and it compounds.
  4. Not using URL state for filters and pagination. The result is pages that reset on refresh.
  5. Using Redux on a greenfield project because the team already knows it. Familiarity is a reason to choose a tool, but the overhead is worth examining before committing.
  6. No selectors in Zustand stores. Components that subscribe to the whole store re-render on every change.
  7. Lifting state too early. Local state should stay local until there is a concrete reason to move it.

A 30 day plan

  1. Week one. Audit the current state layer. List every piece of state by category: server, global UI, form, URL, local. Mark which tool currently owns it and whether that is the right tool.
  2. Week two. Move server data to React Query or SWR if it is currently in a global store. This is almost always the biggest win and the cleanest separation.
  3. Week three. Move filter and pagination values to URL params. Write one shared hook that all filter components use. Test that links are shareable and pages survive refresh.
  4. Week four. Clean up the remaining store. Add selectors to every store subscription. Document the state boundaries for the team.

For deeper reading, zustand vs redux vs jotai vs recoil vs context covers the library comparison in detail, and tRPC vs REST vs GraphQL on the frontend covers the data fetching side of the same architecture question.

FAQ

Frequently asked

Author

The person behind Yashveer Labs

Yashveer Singh, founder of Yashveer Labs. I build full stack systems for clients who care that the thing actually works two years later, not just on launch day. The arc I am on points at machine learning, AI engineering, and cybersecurity. Everything I write here comes from the codebase, not from a content brief. That is the difference and it shows.

Related reading