State Management
Ask developers where their app got complicated and most will point at the same place: state. A counter is trivial, but an app where the cart badge, the checkout total, the saved-items list, and a notification all reflect overlapping data is where bugs breed. The interface shows one number here and a stale one there, and nobody is sure which is right. State management is the part of architecture that prevents exactly that, by being deliberate about where data lives and how it changes.
This guide treats state as a design problem. It extends the data-flow ideas from Foundations and slots into the layered model from client-side architecture.
What you'll learn
What state is, and why it is hard
State is simply the data in your app that changes over time: what the user typed, which tab is open, the items loaded from the server. On its own that is easy. The difficulty is keeping every view that depends on a value showing the same, current value.
State as the source of UI
The healthiest mental model is that the UI is a projection of state: given the state, the view is determined. When that holds, you fix a display bug by fixing the state, not by patching the pixels. Most state nightmares come from breaking this, from letting the same fact live in several places that then drift apart, so the whole discipline is really about protecting that one relationship.
Kinds of state
Before deciding how to manage state, it helps to notice that not all state is the same. Lumping it together is what pushes people to over-centralize.
Local, global, server, and URL state
Local state belongs to one component, like whether a dropdown is open. Global state is shared across the app, like the signed-in user. Server-cache state is data fetched from an API that you hold and refresh, which behaves differently from state you own outright. And the URL itself is state, as the routing guide showed. Classifying a piece of state into one of these tells you where it should live long before you reach for any tool.
A single source of truth
The most important rule in state management is also the simplest to state: each fact should have exactly one home. Copies are the enemy, because copies must be synchronized, and synchronization is where bugs live.
Avoiding duplicated state
If the cart total is stored in three places, sooner or later two of them disagree and the UI contradicts itself. Keep the canonical value in one place and have everything else read from it. A single source of truth does not mean one giant global object; it means no value is duplicated, so there is simply nothing to keep in sync and no opportunity for two screens to show different answers.
Unidirectional data flow
Knowing where state lives is half the picture; the other half is controlling how it changes. Unidirectional data flow makes change predictable by allowing it to move in only one direction.
The one-way update loop
// Single source of truth, one-way updates
var state = { count: 0 };
function dispatch(action) {
state = reducer(state, action); // produce the next state
render(state); // the view follows state
}
State renders the view; the view dispatches an action describing what happened; a function produces the next state; the view re-renders. Because data only ever flows state to view and events flow back as explicit actions, you can trace any change from cause to effect along a single path. This is the same event-driven idea from the events guide, disciplined into a loop, and it is what makes a complex app debuggable.
Derived state, not copies
A lot of accidental duplication comes from storing things that could simply be calculated. If a value can be computed from existing state, computing it is almost always better than storing it.
Compute, don't store
// Derive from the source instead of storing a copy
function completedCount(state) {
return state.todos.filter(function (t) { return t.done; }).length;
}
The number of completed todos is not a separate fact; it is a function of the todos. Deriving it on demand means it can never fall out of step with the list, whereas storing it creates a second value to maintain. Reserve stored state for things you genuinely cannot recompute, and derive everything else with selectors or computed values. Less stored state means fewer chances to be inconsistent.
Choosing how much to centralize
With the principles in place, the practical question is how much machinery to bring in, and the honest answer is usually less than people reach for. Over-centralizing is as harmful as under-managing.
Local by default, global when shared
Keep state local to the component that owns it by default, lift it up only when something else genuinely needs it, and put it in a global store only when it is truly shared across the app. Let the URL hold what belongs in the URL, and treat server data as its own kind of cached state. Matching the tool to the scope, rather than routing every checkbox through a global store, keeps both the code and the data flow simple. With state under control, the next guide looks at how independent components actually talk to each other.
Frequently Asked Questions
What is state management in frontend development?
State management is the practice of organizing the data that changes over time so the interface stays consistent with it. In architecture terms, it is deciding where each piece of state lives, who can change it, and how those changes reach the views that depend on it.
What is a single source of truth?
A single source of truth means each piece of state lives in exactly one canonical place rather than being copied around. With one home per value, there is nothing to keep in sync, so the UI cannot show two different versions of the same thing.
What is unidirectional data flow?
Unidirectional data flow is a one-way loop: state renders the view, the view dispatches an action, and the action produces new state, which renders the view again. Because data only moves in one direction, the path from a change to its effect is easy to follow.
Do I need a state management library?
Not always. Local component state and the URL already cover a great deal, and reaching for a global store too early adds complexity you may not need. A library earns its place when state is shared across many parts of the app or updates become hard to coordinate by hand.
Read next: back to the Frontend Architecture hub, or revisit routing for the URL as state.
Want to see state and views connected?
The complete Backbone guide builds models, collections, and views that stay in sync.
Explore the Backbone Guide →