Choosing Between Signals, Stores, and Context for State in SolidJS
Learn when to use Signals, Stores, and Context in SolidJS to maintain fine-grained reactivity and avoid common pitfalls like reactivity loss through destructuring.
04 Mar 2026, 10:27 UTC

The State Management Dilemma in Fine-Grained Reactivity
In SolidJS, the primary challenge is not whether a component will re-render—since components only run once—but how to ensure the correct DOM node updates when data changes. Choosing the wrong state primitive can lead to unnecessary DOM churn or, more commonly, "lost reactivity" where the UI fails to update because a reactive reference was accidentally broken.
Comparing State Primitives
The decision depends on the shape of your data and how deeply nested your updates are. Use the following table to determine the appropriate tool for your specific constraint.
| Feature | Signals (createSignal) | Stores (createStore) | Context (createContext) |
|---|---|---|---|
| Data Shape | Primitives / Simple Objects | Nested Objects / Arrays | Any Reactive Primitive |
| Update Granularity | Atomic (Whole value) | Path-based (Specific property) | Dependent on wrapped state |
| Reactivity Model | Getter/Setter pair | Proxy-based | Dependency Injection |
| Primary Use Case | Local UI state, toggles | Complex data, API responses | Avoiding prop-drilling |
Trade-offs and Engineering Constraints
Signals are the most performant for single values. However, updating a signal that holds a large object requires replacing the entire object to trigger an update. This can cause every single observer of that object to re-evaluate, even if only one property changed.
Stores solve this via Proxies. A Store allows you to update a deeply nested property (e.g., user.settings.theme) without changing the reference of the user object itself. This ensures that only the DOM element bound to theme updates, leaving the rest of the UI untouched.
Context is not a state primitive itself, but a transport mechanism. It is essential for application-wide state (like authentication) to avoid passing props through ten layers of components. The risk with Context is creating a "god object" that houses too much unrelated state, which can make debugging harder.
Implementation: Granular Store Updates
To implement a Store correctly, you must avoid destructuring. Destructuring a store object (e.g., const { name } = state;) extracts the value at that moment and severs the reactive connection to the Proxy.
Run the following logic within a SolidJS project (v1.0+). Ensure you have solid-js installed in your package manager.
import { createStore } from "solid-js/store";
import { render } from "solid-js/web";
// Initialize store with nested data
const [state, setState] = createStore({
user: {
profile: {
name: "Alice",
preferences: { theme: "light" }
}
}
});
// CORRECT: Path-based update
// This only triggers updates for elements specifically tracking 'theme'
const toggleTheme = () => {
setState("user", "profile", "preferences", "theme", (prev) =>
prev === "light" ? "dark" : "light"
);
};
function App() {
return (
<div>
{/* Accessing via the proxy maintains reactivity */}
<p>Current Theme: {state.user.profile.preferences.theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}
render(<App />, document.getElementById("app"));
Verification and Diagnostics
To verify that your state management is performing granular updates rather than full-component refreshes, you can use the following checks:
- DOM Inspection: Place a
console.log("Render")inside the component body. If you use a Store and update a nested property, the log should not trigger again, as the component function only executes once. - Reference Check: Compare the state object before and after a
setStatecall. In a Store, the top-level object reference remains the same, whereas a Signal update would result in a new object reference.
Limitations
Stores incur a slight memory overhead due to the creation of Proxy objects for every level of nesting. For extremely large lists (thousands of items) where you only need to replace the entire list at once, a Signal holding an array may be more performant than a Store.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.