If everything lives in the store, nothing really lives in the store.
I have watched senior engineers, people with a decade on their resume, answer "how do you structure state in a complex app" by describing one giant global store. Server data, form inputs, a sidebar toggle, a cached auth token, all of it swimming in the same tank like it is 2016 and we are still doing it for the aesthetic. It is the fastest way to turn an architecture interview, and your actual codebase, into a junk drawer.
Here is the thing nobody says out loud: most of what you call "state" is not yours. Server state is someone else's database that you are temporarily babysitting. URL state is free deep-linking infrastructure you already own. Local UI state is just a variable that got ideas above its station. Once you see it that way, the architecture question answers itself: classify first, then pick the tool. The store is a destination you arrive at, not the place everything starts.
Sort every state item into four boxes
This is the whole method, and it fits on an index card. For every piece of state in the app, ask:
-
Did it come from a server? Then it is server state. It is a cache, not state you "manage". Give it a cache (query library with stale-while-revalidate), not a reducer. If you are writing
setServerDataby hand in 2026, you are doing the library's job badly. - Would another person need it from a shared link? Then it belongs in the URL. Query params are the most underused store in frontend: free persistence across refreshes, free deep links, zero code. Search filters, selected tabs, pagination. If a page cannot be shared with a link, you have a bug, not a design choice.
-
Is it only alive inside one component subtree? Local UI state.
useState, colocated with the component that uses it. A modal open flag does not need to travel. If your store has a boolean calledisOpenwith no idea what it opens, I have questions. - Must it survive a reload? Persisted state. localStorage or IndexedDB with a hydration plan and an expiry story. And here is the non-obvious one: persisted state is a cache of a previous session, which makes it server state from the past. Treat it with the same suspicion you would treat any cache.
The decision rule
Copy-paste this into your team's docs:
If you cannot name which of the four boxes a state item belongs in, it does not go in a global store yet.
That one rule kills 80% of store bloat before it starts. The remaining 20% is the genuinely shared, client-owned state: the stuff that is neither server data, nor URL, nor local, nor persisted. That is what your store is for. You will be shocked how small it is.
The interview answer writes itself after that: four boxes, classify first, tools follow. The architecture answer is the same sentence, just slower.
Watch the 40-second version of this idea: https://www.youtube.com/shorts/2k9uY5jQbmY
This is Question 13 of 60 in my Frontend Interview Questions series. The full 60-question playbook, with the system design frameworks behind each answer, is linked on the channel.
Top comments (0)