SolidJS createStore proxy write access and missing read-only boundary
0 reputation · 06 Mar 2022, 13:16 UTC
0 reputation · 06 Mar 2022, 13:16 UTC
SolidJS's createStore returns a Proxy that permits both reads and writes from any scope holding the store reference, with no built-in mechanism to restrict external mutations. In recent releases such as 1.8.x, the library does not provide a native permission boundary or read-only view, leaving encapsulation entirely to the developer.
Because the proxy remains mutable, consumer components or modules that inadvertently receive the store can modify state outside intended actions, causing accidental public access and unpredictable UI updates. Although utilities like immer or custom wrapper proxies can simulate read-only protection, they are not part of the core API and must be implemented and tested manually.
Is there a documented configuration pattern in SolidJS 1.8.x to expose a store as read-only without leaking the underlying mutable proxy? Does the absence of built-in write protection reflect an intentional design choice or an unresolved encapsulation gap? What is the recommended approach for sharing store state across module boundaries while preventing accidental public mutations?
34775 reputation · 06 Mar 2022, 17:32 UTC
SolidJS 1.8.x’s createStore returns a mutable Proxy. The API offers no flag or option to make that proxy read‑only. If you hand the proxy directly to a component or export it from a module, any consumer can mutate the state, which will trigger reactive updates everywhere.
Object.freeze would break dependency tracking.import { createStore } from "solid-js/store";
const [state, setState] = createStore({ count: 0 }); // private
export const getState = () => state;
export const getCount = () => state.count;
export const getSnapshot = () => ({ ...state });
export const increment = () => setState("count", c => c + 1);
setState or the raw proxy unless intentional.If you need to pass immutable data to many consumers, wrap state with produce from immer before sending it out:
import produce from "immer";
export const getImmutable = () => produce(state, draft => draft);
This keeps the original store mutable internally but gives consumers a frozen copy.
Do you currently pass the store proxy directly to child components via props or export it from the module? If so, switching to the pattern above will prevent accidental mutations.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.