Using SolidJS createStore for Scalable State Management
Learn how SolidJS createStore provides a mutable, proxy‑based state solution that cuts boilerplate, keeps updates fine‑grained, and scales with domain‑split stores.
10 Jul 2025, 11:54 UTC

Problem: Managing growing state without boilerplate
As a SolidJS application expands, scattering state across many createSignal calls can lead to repetitive code and difficulty tracking related data. Developers often look for a way to mutate state with familiar JavaScript syntax while still benefiting from Solid’s fine‑grained reactivity.
Thesis: SolidJS’s createStore offers a mutable, proxy‑based store that reduces boilerplate, keeps updates synchronous, and integrates seamlessly with existing rendering primitives.
How createStore works
createStore returns a tuple: a proxy object that mirrors ordinary JavaScript objects and a setter function. Mutations on the proxy are intercepted, batched by Solid’s reactive runtime, and trigger updates only where the changed property is read in the UI.
import { createStore } from 'solid-js/store'
const [state, setState] = createStore({
users: [],
filter: '',
page: 1
})
// Example mutation
setState('users', users => [...users, { id: Date.now(), name: 'Ada' }])
setState('filter', 'solid')
The setter accepts a path (string or array) and an updater function, enabling immutable‑style updates without writing reducers.
Worked example: a filterable user list
The following snippet shows a small component that loads users, lets the user type a filter, and displays the matching rows. Only the filtered list and the input value update when the store changes.
import { For, Show } from 'solid-js'
import { createStore } from 'solid-js/store'
function UserList() {
const [state, setState] = createStore({
users: [],
filter: ''
})
// Simulated data fetch
// In a real app replace with an async call
const init = () => {
setState('users', [
{ id: 1, name: 'Ada Lovelace' },
{ id: 2, name: 'Grace Hopper' },
{ id: 3, name: 'Alan Turing' }
])
}
// Run init once
// (In practice you would use createEffect or onMount)
if (!state.users.length) init()
return (
setState('filter', e.target.value)}
/>
0} fallback={Loading…
}>
u.name.toLowerCase().includes(state.filter.toLowerCase()))}
>{user => (
{user.name}
)}
)
}
When the input changes, only the filter property updates. The For block re‑evaluates its memoized filter function, but the list items themselves are not recreated unless the users array changes.
Trade‑off: deep nesting can cause proxy overhead
If the store contains large, deeply nested objects, each mutation may trigger traversal of the entire proxy tree to detect changes. This overhead is usually negligible for flat or moderately nested state, but can become noticeable with huge trees (e.g., a complex form with thousands of fields).
Mitigation: split the state into multiple stores by domain (e.g., one for UI flags, another for form data) or flatten nested structures where possible. You can also use produce‑like helpers that shallow‑clone only the changed branch.
How to verify the behavior
- Paste the component into the SolidJS Playground.
- Open the SolidJS DevTools (via the browser extension) and select the store from the component tree.
- Type in the input field and observe the DevTools timeline: each keystroke appears as a distinct
setStateaction, but only thefilterproperty is marked as changed. - Replace the store with two separate
createSignalcalls forusersandfilterand compare the number of subscriptions shown in DevTools; you should see a similar count, confirming that the store does not add unnecessary observers.
Actionable closing
If you are building a medium‑size SolidJS app and find yourself passing many signals around or writing boilerplate reducers, try extracting a logical slice of state into a createStore. Start with a flat object, monitor proxy overhead in DevTools, and split the store only when profiling shows a cost. This approach gives you the ergonomics of mutable JavaScript while retaining Solid’s predictable, fine‑grained updates.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.